├── .github └── workflows │ └── lint.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── docs └── source │ └── conf.py ├── poetry.lock ├── poetry.toml ├── pyproject.toml ├── src ├── __init__.py └── sample.py └── tests ├── __init__.py ├── conftest.py └── test_sample.py /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: python lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | paths: 8 | - "src/**.py" 9 | - "tests/**.py" 10 | - "poetry.lock" 11 | - ".github/workflows/lint.yml" 12 | 13 | jobs: 14 | lint: 15 | name: Lint 16 | runs-on: ubuntu-latest 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | python-version: ["3.10"] 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v2 25 | 26 | - name: Set up Python ${{ matrix.python-version }} 27 | uses: actions/setup-python@v2 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | 31 | - name: Install Poetry 32 | run: | 33 | curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - 34 | echo "$HOME/.poetry/bin" >> $GITHUB_PATH 35 | 36 | - uses: actions/cache@v2 37 | id: venv_cache 38 | with: 39 | path: .venv 40 | key: venv-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }} 41 | 42 | - name: Install Dependencies 43 | if: steps.venv_cache.outputs.cache-hit != 'true' 44 | run: poetry install 45 | 46 | - name: Python Lint 47 | run: poetry run task lint 48 | 49 | - name: Python Test 50 | run: poetry run task test 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .env 3 | .python-version 4 | 5 | .coverage 6 | docs/build 7 | dist 8 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.2.0 4 | hooks: 5 | - id: trailing-whitespace 6 | args: [--markdown-linebreak-ext=md] 7 | - id: end-of-file-fixer 8 | - id: mixed-line-ending 9 | args: [--fix=lf] 10 | - id: check-added-large-files 11 | - id: check-toml 12 | - id: check-yaml 13 | - id: detect-aws-credentials 14 | - repo: https://github.com/psf/black 15 | rev: 22.3.0 16 | hooks: 17 | - id: black 18 | language_version: python3 19 | - repo: https://github.com/pre-commit/mirrors-mypy 20 | rev: v0.942 21 | hooks: 22 | - id: mypy 23 | - repo: https://github.com/pycqa/isort 24 | rev: 5.10.1 25 | hooks: 26 | - id: isort 27 | - repo: https://gitlab.com/pycqa/flake8 28 | rev: 4.0.1 29 | hooks: 30 | - id: flake8 31 | additional_dependencies: 32 | - flake8-isort 33 | - flake8-bugbear 34 | - flake8-builtins 35 | - flake8-eradicate 36 | - flake8-pytest-style 37 | - flake8-unused-arguments 38 | - pep8-naming 39 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["ms-python.python", "njpwerner.autodocstring"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[python]": { 3 | "editor.tabSize": 4, 4 | "editor.formatOnSave": true 5 | }, 6 | "python.analysis.extraPaths": ["./src"], 7 | "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", 8 | "python.formatting.provider": "black", 9 | "python.formatting.blackPath": "${workspaceFolder}/.venv/bin/black", 10 | "python.linting.pylintEnabled": false, 11 | "python.linting.flake8Enabled": true, 12 | "python.linting.flake8Path": "${workspaceFolder}/.venv/bin/flake8", 13 | "python.linting.mypyEnabled": true, 14 | "python.linting.mypyPath": "${workspaceFolder}/.venv/bin/mypy", 15 | "python.sortImports.path": "${workspaceFolder}/.venv/bin/isort", 16 | "autoDocstring.docstringFormat": "numpy" 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Project Template 2 | 3 | [![code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black/) [![imports](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) 4 | 5 | 最近、Python の新しいプロジェクトを立ち上げる度に毎回同じような設定をコピペしていたので、テンプレートを用意しとこうと思った次第です。 6 | 7 | - [Python Project Template](#python-project-template) 8 | - [採用技術](#採用技術) 9 | - [前提となるツール](#前提となるツール) 10 | - [Python バージョン管理](#python-バージョン管理) 11 | - [pyenv](#pyenv) 12 | - [パッケージマネージャー](#パッケージマネージャー) 13 | - [poetry](#poetry) 14 | - [リンター (linter)](#リンター-linter) 15 | - [flake8](#flake8) 16 | - [flake8 プラグイン](#flake8-プラグイン) 17 | - [mypy](#mypy) 18 | - [フォーマッター (formatter)](#フォーマッター-formatter) 19 | - [black](#black) 20 | - [isort](#isort) 21 | - [テスティングフレームワーク](#テスティングフレームワーク) 22 | - [pytest](#pytest) 23 | - [ドキュメント生成](#ドキュメント生成) 24 | - [sphinx](#sphinx) 25 | - [タスクランナー](#タスクランナー) 26 | - [taskipy](#taskipy) 27 | - [Git Hooks](#git-hooks) 28 | - [pre-commit](#pre-commit) 29 | - [CI/CD](#cicd) 30 | - [GitHub Actions](#github-actions) 31 | - [VSCode](#vscode) 32 | - [settings.json](#settingsjson) 33 | - [extensions.json](#extensionsjson) 34 | 35 | ## 採用技術 36 | 37 | - python 3.10 38 | - poetry (パッケージ管理) 39 | - flake8, mypy (リンター) 40 | - black, isort (フォーマッター) 41 | - pytest (テスティングフレームワーク) 42 | - sphinx (ドキュメント生成) 43 | - taskipy (タスクランナー) 44 | - pre-commit (git フック) 45 | - github actions (CI/CD) 46 | - vscode (エディタ) 47 | 48 | パッケージ管理には `pipenv` ではなく `poetry` を採用し、 49 | ドキュメント生成には `sphinx` を採用し、 50 | エディタには `vscode` を採用し、 51 | CI/CD は `github actions` でやっちゃってる感じです。 52 | 53 | 当リポジトリを参考にしてくださる方がいる場合は適時不要な技術に関連する設定ファイルは消しちゃって下さい。 54 | 55 | ## 前提となるツール 56 | 57 | - git 58 | - pyenv 59 | - poetry 60 | 61 | この3つはお使いのマシン上で使える状態になっている前提です。 62 | `pyenv` や `poetry` のインストール方法やコマンドの解説も省略しております。 63 | 64 | ## Python バージョン管理 65 | 66 | ### pyenv 67 | 68 | プロジェクトが変われば使用する `python` のバージョンも変わるのが普通なので、同じマシン上でも複数の `python` バージョンを切り替えれるようにしておく必要があり、`pyenv` を採用しています。 69 | 70 | ## パッケージマネージャー 71 | 72 | ### poetry 73 | 74 | `python` のパッケージマネージャーだと `poetry` と `pipenv` が有名ですが、比較記事がたくさんあるので詳しくはググってください。 75 | 76 | ただし、 **インストールについては、公式ドキュメントに書いてある「With the official installer」の方法で行うことをおすすめします** 。 77 | 78 | 79 | 80 | というのも、記事によっては上記公式ドキュメントの「With the official installer」の方ではなく「With pip」のインストール方法が紹介されているのですが、`pip install poetry` でのインストールとなると **pyenv でインストールした python バージョン毎に管理されている `site-packages` ディレクトリ** にインストールされます。 81 | 82 | そのため、pyenv でグローバルの python バージョンを切り替えたら poetry コマンドも使えなくなります。 83 | 84 | 加えて、公式ドキュメントにも 85 | 86 | > Be aware that it will also install Poetry’s dependencies which might cause conflicts with other packages. 87 | 88 | と、他パッケージとの競合に気をつけろよとの警告文があるので、基本的には pip でのインストールはしないほうがいいでしょう。 89 | 90 | ## リンター (linter) 91 | 92 | ### flake8 93 | 94 | python のスタイルガイドである `PEP8` にコードが準拠されているかを検査するリンターとして `pycodestyle` というものがあるのですが、`flake8` は `pycodestyle` を内蔵しており、それに加えて論理エラーまでチェックしてくれるという代物です。 95 | 96 | `pycodestyle` より厳しいリンターと認識しておけばいいと思います。 97 | 98 | ```shell 99 | poetry add -D flake8 100 | ``` 101 | 102 | で開発用パッケージとしてプロジェクトに追加します。 103 | 104 | #### flake8 プラグイン 105 | 106 | `flake8` にはプラグインがたくさんあり、入れれば入れるほど厳しい設定になっていきます。 107 | 108 | 自分で細かくオプションを設定していくことも出来ますが、個人的にはリンターやフォーマッターの設定って凝りすぎると設定ファイルを書く作業にかかる時間がアホみたいに長くなったり、プロジェクト毎のルールの乖離が大きくなってしまってデメリットが大きくなっていくと思っていて(特に `js, ts` のプロジェクトは設定ファイルまみれになるのが苦手...)、極力リンターの設定強化は設定ファイルで行うのではなくプラグインの追加だけで済ませたいという考えです。 109 | 110 | ```shell 111 | poetry add -D flake8-isort flake8-bugbear flake8-builtins flake8-eradicate flake8-unused-arguments flake8-pytest-style pep8-naming 112 | ``` 113 | 114 | 自分は大体上記のプラグインを追加することが多いです。 115 | 116 | - flake8-isort 117 | - import 順が isort (後述) に準拠しているかチェック 118 | - flake8-bugbear 119 | - バグが出やすい箇所に警告を出してくれる 120 | - flake8-builtins 121 | - 変数名/関数名が組み込みオブジェクトと被っていないかチェック 122 | - flake8-eradicate 123 | - コメントアウトされているコードがないかチェック 124 | - flake8-unused-arguments 125 | - 未使用引数がないかチェック 126 | - AWS Lambda の場合 handler の context を使わないケースが多いのでこのプラグインは不向きかもです 127 | - flake8-pytest-style 128 | - pytest (後述) 用のスタイルチェク 129 | - pep8-naming 130 | - 変数名/関数名が PEP8 に準拠しているかチェック 131 | 132 | これ以外にもプラグインはたくさんあるので探してみるとお好みのものが見つかるかもしれません。 133 | 134 | 以下コマンドで `src` ディレクトリ及び `tests` ディレクトリに対して実行出来ます。 135 | このとき、`flake8` コマンドしか実行していませんが、プラグインを追加している場合はそのプラグインの検査も含まれています。 136 | 137 | ```shell 138 | poetry run flake8 src tests 139 | ``` 140 | 141 | ※ 以下 `poetry run` から始まる全てのコマンドの共通事項として、`poetry shell` 後であれば `poetry run` は省略可能 (`flake8 src test` だけでOK) です。 142 | 143 | ### mypy 144 | 145 | 言わずと知れた、`python` で静的型検査をしてくれるツールです。 146 | バグの低減はもちろん、`vscode` 上での補完もゴリゴリに効くようになってコーディングが捗ります。 147 | 148 | ```shell 149 | poetry add -D mypy 150 | ``` 151 | 152 | で開発用パッケージとしてプロジェクトに追加します。 153 | 154 | 加えて、以下のような設定を `pyproject.toml` に記述しています。 155 | テンプレートリポジトリの方ではコメントを書いてませんが、ここでは解説のため各行にコメントを付け加えています。 156 | 157 | ```toml:pyproject.toml 158 | [tool.mypy] 159 | # エラー時のメッセージを詳細表示 160 | show_error_context = true 161 | # エラー発生箇所の行数/列数を表示 162 | show_column_numbers = true 163 | # import 先のチェックを行わない (デフォルトだとサードパーティーライブラリまでチェックする) 164 | ignore_missing_imports = true 165 | # 関数定義の引数/戻り値に型アノテーション必須 166 | disallow_untyped_defs = true 167 | # デフォルト引数に None を取る場合型アノテーションに Optional 必須 168 | no_implicit_optional = true 169 | # 戻り値が Any 型ではない関数の戻り値の型アノテーションが Any のとき警告 170 | warn_return_any = true 171 | # mypy エラーに該当しない箇所に `# type: ignore` コメントが付与されていたら警告 172 | # ※ `# type: ignore` が付与されている箇所は mypy のエラーを無視出来る 173 | warn_unused_ignores = true 174 | # 冗長なキャストに警告 175 | warn_redundant_casts = true 176 | ``` 177 | 178 | 以下コマンドで `src` ディレクトリ及び `tests` ディレクトリに対して実行出来ます。 179 | 180 | ```shell 181 | poetry run mypy src tests 182 | ``` 183 | 184 | ## フォーマッター (formatter) 185 | 186 | ### black 187 | 188 | 総合的な `python` フォーマッターで、`eslint` など他言語のフォーマッターと比べて自分で設定する箇所が少ないところが気に入っています。 189 | 190 | ```shell 191 | poetry add -D black 192 | ``` 193 | 194 | で開発用パッケージとしてプロジェクトに追加します。 195 | 196 | デフォルトだと1行の最大文字数が 88 になっているのですが、`PEP8` に合わせて79文字にするため、`pyproject.toml` に以下の設定をしています。 197 | 198 | ```toml:pyproject.toml 199 | [tool.black] 200 | line-length = 79 201 | ``` 202 | 203 | この辺は好みなので気にならない人は設定しなくてもいいと思います。 204 | 205 | 以下コマンドで `src` ディレクトリ及び `tests` ディレクトリに対して実行出来ます。 206 | 207 | ```shell 208 | poetry run black src tests 209 | ``` 210 | 211 | また、`--check` オプションを付与することで、フォーマットを実行せずに「フォーマットが必要な箇所があるか」を検査出来ます。 212 | `CI` 等で `lint` のステップに組み込むと良いです。 213 | 214 | ```shell 215 | poetry run black --check src tests 216 | ``` 217 | 218 | ### isort 219 | 220 | `import` の順番を 221 | 222 | 1. 組み込みライブラリ 223 | 2. サードパーティーライブラリ 224 | 3. 自作ライブラリ 225 | 226 | かつ、1~3 の中でアルファベット順に並び替えてくれます。 227 | 228 | ```shell 229 | poetry add -D isort 230 | ``` 231 | 232 | で開発用パッケージとしてプロジェクトに追加します。 233 | 234 | `black` と併用する都合 `pyproject.toml` に以下の設定をしています。 235 | 236 | ```toml:pyproject.toml 237 | [tool.isort] 238 | profile = "black" 239 | line_length = 79 240 | ``` 241 | 242 | 以下コマンドで `src` ディレクトリ及び `tests` ディレクトリに対して実行出来ます。 243 | 244 | ```shell 245 | poetry run isort src tests 246 | ``` 247 | 248 | ## テスティングフレームワーク 249 | 250 | ### pytest 251 | 252 | たぶんデファクトスタンダードでしょう。 253 | テストコードを書かない場合は不要です。 254 | 255 | ```shell 256 | poetry add -D pytest pytest-mock pytest-cov 257 | ``` 258 | 259 | で開発用パッケージとしてプロジェクトに追加します。 260 | 261 | `pytest-mock` はモック作成用、`pytest-cov` はカバレッジ出力のために使用します。 262 | 263 | カバレッジ出力を `html` で行うと以下のような形になります。 264 | 265 | ```shell 266 | poetry run pytest -s -vv --cov=. --cov-branch --cov-report=html 267 | ``` 268 | 269 | ![pytest-cov-1](https://storage.googleapis.com/zenn-user-upload/c34e0735a18a-20220418.png) 270 | ![pytest-cov-2](https://storage.googleapis.com/zenn-user-upload/35ff38778061-20220418.png) 271 | 272 | テストコードの書き方についてはここでは触れませんが、リポジトリに簡単なサンプルだけ含まれてます。 273 | 274 | ## ドキュメント生成 275 | 276 | ### sphinx 277 | 278 | ドキュメントの生成には `sphinx` を採用してます。 279 | `python` のライブラリのドキュメントでよく見かける [こんな見た目のやつ](https://sphinx-rtd-theme.readthedocs.io/en/stable/) です 280 | 281 | ```shell 282 | poetry add -D Sphinx sphinx-rtd-theme sphinx-pyproject 283 | ``` 284 | 285 | で開発用パッケージとしてプロジェクトに追加します。 286 | 287 | `sphinx-rtd-theme` はテーマを [これ](https://sphinx-rtd-theme.readthedocs.io/en/stable/) にするために、`sphinx-pyproject` は `sphinx` の設定を `pyproject.toml` で一元管理するためにインストールしています。 288 | 289 | `pyproject.toml` に以下の記述を追記します。 290 | 各パラメータに設定している値は適時修正してください。 291 | 292 | ```toml:pyproject.toml 293 | [project] 294 | name = "python-template" 295 | version = "0.1.0" 296 | description = "Python Project の Template" 297 | readme = "README.md" 298 | 299 | [[project.authors]] 300 | name = "jDBTISK" 301 | 302 | [tool.sphinx-pyproject] 303 | project = "python-template" 304 | copyright = "2022, jDBTISK" 305 | language = "en" 306 | package_root = "python-template" 307 | html_theme = "sphinx_rtd_theme" 308 | todo_include_todos = true 309 | templates_path = ["_templates"] 310 | html_static_path = ["_static"] 311 | extensions = [ 312 | "sphinx.ext.autodoc", 313 | "sphinx.ext.viewcode", 314 | "sphinx.ext.todo", 315 | "sphinx.ext.napoleon", 316 | ] 317 | ``` 318 | 319 | 加えて、`docs/source/conf.py` を作成します。 320 | `sphinx-pyproject` を使用していない場合、このファイルに上記の `pyproject.toml` に追記したような内容を書いていかなければいけないんですが、ここでは以下のコードをコピペするだけで OK です。 321 | 322 | ```python:docs/source/conf.py 323 | import os 324 | import sys 325 | 326 | from sphinx_pyproject import SphinxConfig 327 | 328 | sys.path.append( 329 | os.path.abspath(f"{os.path.dirname(os.path.abspath(__file__))}/../../") 330 | ) 331 | 332 | config = SphinxConfig("../../pyproject.toml", globalns=globals()) 333 | ``` 334 | 335 | この設定でテンプレートリポジトリに含まれているソースコードを対象にドキュメントを生成すると以下のようになります。 336 | 337 | ```shell 338 | poetry run sphinx-apidoc -F -o docs/source src 339 | poetry run sphinx-build docs/source docs/build 340 | ``` 341 | 342 | ![sphinx-1](https://storage.googleapis.com/zenn-user-upload/47691d38da65-20220418.png) 343 | ![sphinx-2](https://storage.googleapis.com/zenn-user-upload/b67d37f8502e-20220418.png) 344 | 345 | ## タスクランナー 346 | 347 | ### taskipy 348 | 349 | タスクランナーというのは簡単に言うと `node` で言う `npm run ~~~` みたいにコマンドのエイリアスを設定ファイルに書いておけるやつです。 350 | 351 | `poetry` にはデフォルトでタスクランナーが搭載されているわけではないですが、サードパーティーの `taskipy` というライブラリをインストールすることでタスクランナーを使用出来ます。 352 | 353 | ```shell 354 | poetry add -D taskipy 355 | ``` 356 | 357 | で開発用パッケージとしてプロジェクトに追加します。 358 | 359 | タスクランナーとして使うためには `pyproject.toml` に以下のような記述をします。 360 | 361 | ```toml:pyproject.toml 362 | [tool.taskipy.tasks] 363 | test = "pytest -s -vv --cov=. --cov-branch --cov-report=html" 364 | fmt = "task fmt-black && task fmt-isort" 365 | fmt-black = "black src tests" 366 | fmt-isort = "isort src tests" 367 | lint = "task lint-black && task lint-flake8 && task lint-mypy" 368 | lint-flake8 = "flake8 src tests" 369 | lint-mypy = "mypy src tests" 370 | lint-black = "black --check src tests" 371 | docs = "sphinx-apidoc -F -o docs/source src && sphinx-build docs/source docs/build" 372 | ``` 373 | 374 | 実行コマンドは `poetry run task タスク名` です。 375 | これでフォーマッターやリンター、ドキュメント生成等のコマンドをいちいち覚える必要がなくなるので楽です。 376 | 377 | ```shell 378 | # テスト実行 379 | poetry run task test 380 | # フォーマッター実行 381 | poetry run task fmt 382 | # リンター実行 383 | poetry run task lint 384 | # ドキュメント出力 385 | poetry run task docs 386 | ``` 387 | 388 | `poetry shell` 中であれば `poetry run` を省略出来るので `task test` だけでテスト実行になります。 389 | 390 | ## Git Hooks 391 | 392 | ### pre-commit 393 | 394 | `.pre-commit-config.yaml` という設定ファイルを使って `pre-commit` の設定が出来ます。 395 | 396 | `pre-commit` というのは `git commit` 実行時にコミット前に走るスクリプトになります。 397 | 398 | ```shell 399 | poetry add -D pre-commit 400 | ``` 401 | 402 | で開発用パッケージとしてプロジェクトに追加します。 403 | 404 | `.pre-commit-config.yaml` ファイルをプロジェクトのルートに作成します。 405 | テンプレートリポジトリの方ではコメントを書いてませんが、ここでは解説のためコメントを付け加えています。 406 | 407 | ```yml:.pre-commit-config.yaml 408 | repos: 409 | # hooks script のソースリポジトリ 410 | - repo: https://github.com/pre-commit/pre-commit-hooks 411 | # リポジトリのブランチ or タグ 412 | rev: v4.2.0 413 | # 使用したい hook script の指定 414 | hooks: 415 | # markdown 以外の行末スペース削除 416 | - id: trailing-whitespace 417 | args: [--markdown-linebreak-ext=md] 418 | # ファイル最終行を改行コードにする 419 | - id: end-of-file-fixer 420 | # 改行コードを LF に統一 421 | - id: mixed-line-ending 422 | args: [--fix=lf] 423 | # 巨大なファイルの commit を禁止 424 | - id: check-added-large-files 425 | # toml 構文チェック 426 | - id: check-toml 427 | # yaml 構文チェック 428 | - id: check-yaml 429 | # aws の認証情報が含まれていないかチェック 430 | - id: detect-aws-credentials 431 | - repo: https://github.com/psf/black 432 | rev: 22.3.0 433 | hooks: 434 | # black によるフォーマット実行 435 | - id: black 436 | language_version: python3 437 | - repo: https://github.com/pre-commit/mirrors-mypy 438 | rev: v0.942 439 | hooks: 440 | # mypy による型チェック実行 441 | - id: mypy 442 | - repo: https://github.com/pycqa/isort 443 | rev: 5.10.1 444 | hooks: 445 | # isort によるフォーマット実行 446 | - id: isort 447 | - repo: https://gitlab.com/pycqa/flake8 448 | rev: 4.0.1 449 | hooks: 450 | # flake8 によるコードチェック実行 451 | - id: flake8 452 | # 使用する flake8 プラグイン 453 | additional_dependencies: 454 | - flake8-isort 455 | - flake8-bugbear 456 | - flake8-builtins 457 | - flake8-eradicate 458 | - flake8-pytest-style 459 | - flake8-unused-arguments 460 | - pep8-naming 461 | ``` 462 | 463 | このファイルを書いたら、以下コマンドで `git hook` スクリプトをセットアップします。 464 | 465 | ```shell 466 | poetry run pre-commit install 467 | ``` 468 | 469 | 以降、このリポジトリで `git commit` しようとすると `.pre-commit-config.yaml` に書いた設定に従った各種チェックが入り、違反しているものがあればコミット自体されません。 470 | 471 | ## CI/CD 472 | 473 | ### GitHub Actions 474 | 475 | これに関しては好みの差以前に利用する `git` のホスティングサービスによって使えるものが変わったりもすると思いますが、とりあえず自分が `github` で `python` リポジトリ作る場合によく書く `workflow` になります。 476 | 477 | ```yml:.github/workflows/lint.yml 478 | name: python lint 479 | 480 | on: 481 | # main ブランチ向けのプルリク作成時、及び 482 | # main ブランチ向けプルリクのソースブランチへの push 時に workflow 実行 483 | pull_request: 484 | branches: 485 | - main 486 | # python ファイル or 使用するライブラリ (poetry.lock) or このファイル 487 | # に変更があったときだけ workflow 実行 488 | paths: 489 | - "src/**.py" 490 | - "tests/**.py" 491 | - "poetry.lock" 492 | - ".github/workflows/lint.yml" 493 | 494 | jobs: 495 | lint: 496 | name: Lint 497 | runs-on: ubuntu-latest 498 | strategy: 499 | fail-fast: false 500 | # ここで指定するバージョンを増やせば複数の python バージョンで各 step を実行出来ます 501 | # ライブラリを作っていて対応している python バージョン全てで test を行いたいときに便利です 502 | matrix: 503 | python-version: ["3.10"] 504 | 505 | steps: 506 | - name: Checkout 507 | uses: actions/checkout@v2 508 | 509 | - name: Set up Python ${{ matrix.python-version }} 510 | uses: actions/setup-python@v2 511 | with: 512 | python-version: ${{ matrix.python-version }} 513 | 514 | - name: Install Poetry 515 | run: | 516 | curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - 517 | echo "$HOME/.poetry/bin" >> $GITHUB_PATH 518 | 519 | # .venv ディレクトリをキャッシュ 520 | - uses: actions/cache@v2 521 | id: venv_cache 522 | with: 523 | path: .venv 524 | key: venv-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }} 525 | 526 | # poetry.lock ファイルに変更がなければキャッシュされている .venv を使用 527 | - name: Install Dependencies 528 | if: steps.venv_cache.outputs.cache-hit != 'true' 529 | run: poetry install 530 | 531 | - name: Python Lint 532 | run: poetry run task lint 533 | 534 | - name: Python Test 535 | run: poetry run task test 536 | ``` 537 | 538 | 加えてデプロイ用の workflow も入ってくる感じになると思いますが、デプロイ先によって全然違うものになってくるのでテンプレートには含めていません。 539 | 540 | ## VSCode 541 | 542 | ### settings.json 543 | 544 | `vscode` を使用する場合、プロジェクトのルートに `.vscode/settings.json` があるとその設定がプロジェクト内のみ有効になります。 545 | 546 | ```json:.vscode/settings.json 547 | { 548 | "[python]": { 549 | // タブサイズは 4 550 | "editor.tabSize": 4, 551 | // ファイル保存時にフォーマット 552 | "editor.formatOnSave": true 553 | }, 554 | // tests ディレクトリから src ディレクトリのモジュールをインポートするときの vscode 上でモジュールが見つからないエラー防止 555 | "python.analysis.extraPaths": ["./src"], 556 | // .venv 内の python を使用 557 | "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", 558 | // フォーマッターは black を使用 559 | "python.formatting.provider": "black", 560 | "python.formatting.blackPath": "${workspaceFolder}/.venv/bin/black", 561 | "python.sortImports.path": "${workspaceFolder}/.venv/bin/isort", 562 | // リンターに flake8 と mypy を使用 563 | "python.linting.pylintEnabled": false, 564 | "python.linting.flake8Enabled": true, 565 | "python.linting.flake8Path": "${workspaceFolder}/.venv/bin/flake8", 566 | "python.linting.mypyEnabled": true, 567 | "python.linting.mypyPath": "${workspaceFolder}/.venv/bin/mypy", 568 | // docstring は nympy スタイル (ここは完全好みです) 569 | "autoDocstring.docstringFormat": "numpy" 570 | } 571 | ``` 572 | 573 | この設定で、`vscode` 上で `python` ファイルを編集すると、ファイル保存時に自動で `black` のフォーマットが効いたり、コーディング中に `flake8` や `mypy` の違反があればエラーが出てくれます。 574 | 575 | ### extensions.json 576 | 577 | 先程 `.vscode/settings.json` について紹介しましたが、拡張機能が前提となっている設定も混ざっているので、`.vscode/extensions.json` も書いてあげると親切です。 578 | 579 | ```json:.vscode/extensions.json 580 | { 581 | "recommendations": ["ms-python.python", "njpwerner.autodocstring"] 582 | } 583 | ``` 584 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from sphinx_pyproject import SphinxConfig 5 | 6 | sys.path.append( 7 | os.path.abspath(f"{os.path.dirname(os.path.abspath(__file__))}/../../") 8 | ) 9 | 10 | config = SphinxConfig("../../pyproject.toml", globalns=globals()) 11 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "alabaster" 3 | version = "0.7.12" 4 | description = "A configurable sidebar-enabled Sphinx theme" 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "atomicwrites" 11 | version = "1.4.0" 12 | description = "Atomic file writes." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 16 | 17 | [[package]] 18 | name = "attrs" 19 | version = "21.4.0" 20 | description = "Classes Without Boilerplate" 21 | category = "dev" 22 | optional = false 23 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 24 | 25 | [package.extras] 26 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] 27 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] 28 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] 29 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] 30 | 31 | [[package]] 32 | name = "babel" 33 | version = "2.9.1" 34 | description = "Internationalization utilities" 35 | category = "dev" 36 | optional = false 37 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 38 | 39 | [package.dependencies] 40 | pytz = ">=2015.7" 41 | 42 | [[package]] 43 | name = "black" 44 | version = "22.3.0" 45 | description = "The uncompromising code formatter." 46 | category = "dev" 47 | optional = false 48 | python-versions = ">=3.6.2" 49 | 50 | [package.dependencies] 51 | click = ">=8.0.0" 52 | mypy-extensions = ">=0.4.3" 53 | pathspec = ">=0.9.0" 54 | platformdirs = ">=2" 55 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 56 | 57 | [package.extras] 58 | colorama = ["colorama (>=0.4.3)"] 59 | d = ["aiohttp (>=3.7.4)"] 60 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 61 | uvloop = ["uvloop (>=0.15.2)"] 62 | 63 | [[package]] 64 | name = "certifi" 65 | version = "2021.10.8" 66 | description = "Python package for providing Mozilla's CA Bundle." 67 | category = "dev" 68 | optional = false 69 | python-versions = "*" 70 | 71 | [[package]] 72 | name = "cfgv" 73 | version = "3.3.1" 74 | description = "Validate configuration and produce human readable error messages." 75 | category = "dev" 76 | optional = false 77 | python-versions = ">=3.6.1" 78 | 79 | [[package]] 80 | name = "charset-normalizer" 81 | version = "2.0.12" 82 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 83 | category = "dev" 84 | optional = false 85 | python-versions = ">=3.5.0" 86 | 87 | [package.extras] 88 | unicode_backport = ["unicodedata2"] 89 | 90 | [[package]] 91 | name = "click" 92 | version = "8.1.2" 93 | description = "Composable command line interface toolkit" 94 | category = "dev" 95 | optional = false 96 | python-versions = ">=3.7" 97 | 98 | [package.dependencies] 99 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 100 | 101 | [[package]] 102 | name = "colorama" 103 | version = "0.4.4" 104 | description = "Cross-platform colored terminal text." 105 | category = "dev" 106 | optional = false 107 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 108 | 109 | [[package]] 110 | name = "coverage" 111 | version = "6.3.2" 112 | description = "Code coverage measurement for Python" 113 | category = "dev" 114 | optional = false 115 | python-versions = ">=3.7" 116 | 117 | [package.dependencies] 118 | tomli = {version = "*", optional = true, markers = "extra == \"toml\""} 119 | 120 | [package.extras] 121 | toml = ["tomli"] 122 | 123 | [[package]] 124 | name = "distlib" 125 | version = "0.3.4" 126 | description = "Distribution utilities" 127 | category = "dev" 128 | optional = false 129 | python-versions = "*" 130 | 131 | [[package]] 132 | name = "docutils" 133 | version = "0.17.1" 134 | description = "Docutils -- Python Documentation Utilities" 135 | category = "dev" 136 | optional = false 137 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 138 | 139 | [[package]] 140 | name = "dom-toml" 141 | version = "0.5.1.post1" 142 | description = "Dom's tools for Tom's Obvious, Minimal Language." 143 | category = "dev" 144 | optional = false 145 | python-versions = ">=3.6.1" 146 | 147 | [package.dependencies] 148 | domdf-python-tools = ">=2.8.0" 149 | toml = ">=0.10.2" 150 | 151 | [[package]] 152 | name = "domdf-python-tools" 153 | version = "3.2.2.post1" 154 | description = "Helpful functions for Python 🐍 🛠️" 155 | category = "dev" 156 | optional = false 157 | python-versions = ">=3.6" 158 | 159 | [package.dependencies] 160 | natsort = ">=7.0.1" 161 | typing-extensions = ">=3.7.4.1" 162 | 163 | [package.extras] 164 | all = ["pytz (>=2019.1)"] 165 | dates = ["pytz (>=2019.1)"] 166 | 167 | [[package]] 168 | name = "eradicate" 169 | version = "2.1.0" 170 | description = "Removes commented-out code." 171 | category = "dev" 172 | optional = false 173 | python-versions = "*" 174 | 175 | [[package]] 176 | name = "filelock" 177 | version = "3.6.0" 178 | description = "A platform independent file lock." 179 | category = "dev" 180 | optional = false 181 | python-versions = ">=3.7" 182 | 183 | [package.extras] 184 | docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] 185 | testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] 186 | 187 | [[package]] 188 | name = "flake8" 189 | version = "4.0.1" 190 | description = "the modular source code checker: pep8 pyflakes and co" 191 | category = "dev" 192 | optional = false 193 | python-versions = ">=3.6" 194 | 195 | [package.dependencies] 196 | mccabe = ">=0.6.0,<0.7.0" 197 | pycodestyle = ">=2.8.0,<2.9.0" 198 | pyflakes = ">=2.4.0,<2.5.0" 199 | 200 | [[package]] 201 | name = "flake8-bugbear" 202 | version = "22.3.23" 203 | description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." 204 | category = "dev" 205 | optional = false 206 | python-versions = ">=3.6" 207 | 208 | [package.dependencies] 209 | attrs = ">=19.2.0" 210 | flake8 = ">=3.0.0" 211 | 212 | [package.extras] 213 | dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"] 214 | 215 | [[package]] 216 | name = "flake8-builtins" 217 | version = "1.5.3" 218 | description = "Check for python builtins being used as variables or parameters." 219 | category = "dev" 220 | optional = false 221 | python-versions = "*" 222 | 223 | [package.dependencies] 224 | flake8 = "*" 225 | 226 | [package.extras] 227 | test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"] 228 | 229 | [[package]] 230 | name = "flake8-eradicate" 231 | version = "1.2.0" 232 | description = "Flake8 plugin to find commented out code" 233 | category = "dev" 234 | optional = false 235 | python-versions = ">=3.6,<4.0" 236 | 237 | [package.dependencies] 238 | attrs = "*" 239 | eradicate = ">=2.0,<3.0" 240 | flake8 = ">=3.5,<5" 241 | 242 | [[package]] 243 | name = "flake8-isort" 244 | version = "4.1.1" 245 | description = "flake8 plugin that integrates isort ." 246 | category = "dev" 247 | optional = false 248 | python-versions = "*" 249 | 250 | [package.dependencies] 251 | flake8 = ">=3.2.1,<5" 252 | isort = ">=4.3.5,<6" 253 | testfixtures = ">=6.8.0,<7" 254 | 255 | [package.extras] 256 | test = ["pytest-cov"] 257 | 258 | [[package]] 259 | name = "flake8-plugin-utils" 260 | version = "1.3.2" 261 | description = "The package provides base classes and utils for flake8 plugin writing" 262 | category = "dev" 263 | optional = false 264 | python-versions = ">=3.6,<4.0" 265 | 266 | [[package]] 267 | name = "flake8-polyfill" 268 | version = "1.0.2" 269 | description = "Polyfill package for Flake8 plugins" 270 | category = "dev" 271 | optional = false 272 | python-versions = "*" 273 | 274 | [package.dependencies] 275 | flake8 = "*" 276 | 277 | [[package]] 278 | name = "flake8-pytest-style" 279 | version = "1.6.0" 280 | description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests." 281 | category = "dev" 282 | optional = false 283 | python-versions = ">=3.6.2,<4.0.0" 284 | 285 | [package.dependencies] 286 | flake8-plugin-utils = ">=1.3.2,<2.0.0" 287 | 288 | [[package]] 289 | name = "flake8-unused-arguments" 290 | version = "0.0.9" 291 | description = "flake8 extension to warn on unused function arguments" 292 | category = "dev" 293 | optional = false 294 | python-versions = "*" 295 | 296 | [package.dependencies] 297 | flake8 = ">3.0.0" 298 | 299 | [[package]] 300 | name = "identify" 301 | version = "2.4.12" 302 | description = "File identification library for Python" 303 | category = "dev" 304 | optional = false 305 | python-versions = ">=3.7" 306 | 307 | [package.extras] 308 | license = ["ukkonen"] 309 | 310 | [[package]] 311 | name = "idna" 312 | version = "3.3" 313 | description = "Internationalized Domain Names in Applications (IDNA)" 314 | category = "dev" 315 | optional = false 316 | python-versions = ">=3.5" 317 | 318 | [[package]] 319 | name = "imagesize" 320 | version = "1.3.0" 321 | description = "Getting image size from png/jpeg/jpeg2000/gif file" 322 | category = "dev" 323 | optional = false 324 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 325 | 326 | [[package]] 327 | name = "iniconfig" 328 | version = "1.1.1" 329 | description = "iniconfig: brain-dead simple config-ini parsing" 330 | category = "dev" 331 | optional = false 332 | python-versions = "*" 333 | 334 | [[package]] 335 | name = "isort" 336 | version = "5.10.1" 337 | description = "A Python utility / library to sort Python imports." 338 | category = "dev" 339 | optional = false 340 | python-versions = ">=3.6.1,<4.0" 341 | 342 | [package.extras] 343 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 344 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 345 | colors = ["colorama (>=0.4.3,<0.5.0)"] 346 | plugins = ["setuptools"] 347 | 348 | [[package]] 349 | name = "jinja2" 350 | version = "3.1.1" 351 | description = "A very fast and expressive template engine." 352 | category = "dev" 353 | optional = false 354 | python-versions = ">=3.7" 355 | 356 | [package.dependencies] 357 | MarkupSafe = ">=2.0" 358 | 359 | [package.extras] 360 | i18n = ["Babel (>=2.7)"] 361 | 362 | [[package]] 363 | name = "markupsafe" 364 | version = "2.1.1" 365 | description = "Safely add untrusted strings to HTML/XML markup." 366 | category = "dev" 367 | optional = false 368 | python-versions = ">=3.7" 369 | 370 | [[package]] 371 | name = "mccabe" 372 | version = "0.6.1" 373 | description = "McCabe checker, plugin for flake8" 374 | category = "dev" 375 | optional = false 376 | python-versions = "*" 377 | 378 | [[package]] 379 | name = "mslex" 380 | version = "0.3.0" 381 | description = "shlex for windows" 382 | category = "dev" 383 | optional = false 384 | python-versions = ">=3.5" 385 | 386 | [[package]] 387 | name = "mypy" 388 | version = "0.942" 389 | description = "Optional static typing for Python" 390 | category = "dev" 391 | optional = false 392 | python-versions = ">=3.6" 393 | 394 | [package.dependencies] 395 | mypy-extensions = ">=0.4.3" 396 | tomli = ">=1.1.0" 397 | typing-extensions = ">=3.10" 398 | 399 | [package.extras] 400 | dmypy = ["psutil (>=4.0)"] 401 | python2 = ["typed-ast (>=1.4.0,<2)"] 402 | reports = ["lxml"] 403 | 404 | [[package]] 405 | name = "mypy-extensions" 406 | version = "0.4.3" 407 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 408 | category = "dev" 409 | optional = false 410 | python-versions = "*" 411 | 412 | [[package]] 413 | name = "natsort" 414 | version = "8.1.0" 415 | description = "Simple yet flexible natural sorting in Python." 416 | category = "dev" 417 | optional = false 418 | python-versions = ">=3.6" 419 | 420 | [package.extras] 421 | fast = ["fastnumbers (>=2.0.0)"] 422 | icu = ["PyICU (>=1.0.0)"] 423 | 424 | [[package]] 425 | name = "nodeenv" 426 | version = "1.6.0" 427 | description = "Node.js virtual environment builder" 428 | category = "dev" 429 | optional = false 430 | python-versions = "*" 431 | 432 | [[package]] 433 | name = "packaging" 434 | version = "21.3" 435 | description = "Core utilities for Python packages" 436 | category = "dev" 437 | optional = false 438 | python-versions = ">=3.6" 439 | 440 | [package.dependencies] 441 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 442 | 443 | [[package]] 444 | name = "pathspec" 445 | version = "0.9.0" 446 | description = "Utility library for gitignore style pattern matching of file paths." 447 | category = "dev" 448 | optional = false 449 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 450 | 451 | [[package]] 452 | name = "pep8-naming" 453 | version = "0.12.1" 454 | description = "Check PEP-8 naming conventions, plugin for flake8" 455 | category = "dev" 456 | optional = false 457 | python-versions = "*" 458 | 459 | [package.dependencies] 460 | flake8 = ">=3.9.1" 461 | flake8-polyfill = ">=1.0.2,<2" 462 | 463 | [[package]] 464 | name = "platformdirs" 465 | version = "2.5.1" 466 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 467 | category = "dev" 468 | optional = false 469 | python-versions = ">=3.7" 470 | 471 | [package.extras] 472 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] 473 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 474 | 475 | [[package]] 476 | name = "pluggy" 477 | version = "1.0.0" 478 | description = "plugin and hook calling mechanisms for python" 479 | category = "dev" 480 | optional = false 481 | python-versions = ">=3.6" 482 | 483 | [package.extras] 484 | dev = ["pre-commit", "tox"] 485 | testing = ["pytest", "pytest-benchmark"] 486 | 487 | [[package]] 488 | name = "pre-commit" 489 | version = "2.18.1" 490 | description = "A framework for managing and maintaining multi-language pre-commit hooks." 491 | category = "dev" 492 | optional = false 493 | python-versions = ">=3.7" 494 | 495 | [package.dependencies] 496 | cfgv = ">=2.0.0" 497 | identify = ">=1.0.0" 498 | nodeenv = ">=0.11.1" 499 | pyyaml = ">=5.1" 500 | toml = "*" 501 | virtualenv = ">=20.0.8" 502 | 503 | [[package]] 504 | name = "psutil" 505 | version = "5.9.0" 506 | description = "Cross-platform lib for process and system monitoring in Python." 507 | category = "dev" 508 | optional = false 509 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 510 | 511 | [package.extras] 512 | test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] 513 | 514 | [[package]] 515 | name = "py" 516 | version = "1.11.0" 517 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 518 | category = "dev" 519 | optional = false 520 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 521 | 522 | [[package]] 523 | name = "pycodestyle" 524 | version = "2.8.0" 525 | description = "Python style guide checker" 526 | category = "dev" 527 | optional = false 528 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 529 | 530 | [[package]] 531 | name = "pyflakes" 532 | version = "2.4.0" 533 | description = "passive checker of Python programs" 534 | category = "dev" 535 | optional = false 536 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 537 | 538 | [[package]] 539 | name = "pygments" 540 | version = "2.11.2" 541 | description = "Pygments is a syntax highlighting package written in Python." 542 | category = "dev" 543 | optional = false 544 | python-versions = ">=3.5" 545 | 546 | [[package]] 547 | name = "pyparsing" 548 | version = "3.0.8" 549 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 550 | category = "dev" 551 | optional = false 552 | python-versions = ">=3.6.8" 553 | 554 | [package.extras] 555 | diagrams = ["railroad-diagrams", "jinja2"] 556 | 557 | [[package]] 558 | name = "pytest" 559 | version = "7.1.1" 560 | description = "pytest: simple powerful testing with Python" 561 | category = "dev" 562 | optional = false 563 | python-versions = ">=3.7" 564 | 565 | [package.dependencies] 566 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 567 | attrs = ">=19.2.0" 568 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 569 | iniconfig = "*" 570 | packaging = "*" 571 | pluggy = ">=0.12,<2.0" 572 | py = ">=1.8.2" 573 | tomli = ">=1.0.0" 574 | 575 | [package.extras] 576 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 577 | 578 | [[package]] 579 | name = "pytest-cov" 580 | version = "3.0.0" 581 | description = "Pytest plugin for measuring coverage." 582 | category = "dev" 583 | optional = false 584 | python-versions = ">=3.6" 585 | 586 | [package.dependencies] 587 | coverage = {version = ">=5.2.1", extras = ["toml"]} 588 | pytest = ">=4.6" 589 | 590 | [package.extras] 591 | testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] 592 | 593 | [[package]] 594 | name = "pytest-mock" 595 | version = "3.7.0" 596 | description = "Thin-wrapper around the mock package for easier use with pytest" 597 | category = "dev" 598 | optional = false 599 | python-versions = ">=3.7" 600 | 601 | [package.dependencies] 602 | pytest = ">=5.0" 603 | 604 | [package.extras] 605 | dev = ["pre-commit", "tox", "pytest-asyncio"] 606 | 607 | [[package]] 608 | name = "pytz" 609 | version = "2022.1" 610 | description = "World timezone definitions, modern and historical" 611 | category = "dev" 612 | optional = false 613 | python-versions = "*" 614 | 615 | [[package]] 616 | name = "pyyaml" 617 | version = "6.0" 618 | description = "YAML parser and emitter for Python" 619 | category = "dev" 620 | optional = false 621 | python-versions = ">=3.6" 622 | 623 | [[package]] 624 | name = "requests" 625 | version = "2.27.1" 626 | description = "Python HTTP for Humans." 627 | category = "dev" 628 | optional = false 629 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 630 | 631 | [package.dependencies] 632 | certifi = ">=2017.4.17" 633 | charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} 634 | idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} 635 | urllib3 = ">=1.21.1,<1.27" 636 | 637 | [package.extras] 638 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 639 | use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] 640 | 641 | [[package]] 642 | name = "six" 643 | version = "1.16.0" 644 | description = "Python 2 and 3 compatibility utilities" 645 | category = "dev" 646 | optional = false 647 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 648 | 649 | [[package]] 650 | name = "snowballstemmer" 651 | version = "2.2.0" 652 | description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." 653 | category = "dev" 654 | optional = false 655 | python-versions = "*" 656 | 657 | [[package]] 658 | name = "sphinx" 659 | version = "4.5.0" 660 | description = "Python documentation generator" 661 | category = "dev" 662 | optional = false 663 | python-versions = ">=3.6" 664 | 665 | [package.dependencies] 666 | alabaster = ">=0.7,<0.8" 667 | babel = ">=1.3" 668 | colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} 669 | docutils = ">=0.14,<0.18" 670 | imagesize = "*" 671 | Jinja2 = ">=2.3" 672 | packaging = "*" 673 | Pygments = ">=2.0" 674 | requests = ">=2.5.0" 675 | snowballstemmer = ">=1.1" 676 | sphinxcontrib-applehelp = "*" 677 | sphinxcontrib-devhelp = "*" 678 | sphinxcontrib-htmlhelp = ">=2.0.0" 679 | sphinxcontrib-jsmath = "*" 680 | sphinxcontrib-qthelp = "*" 681 | sphinxcontrib-serializinghtml = ">=1.1.5" 682 | 683 | [package.extras] 684 | docs = ["sphinxcontrib-websupport"] 685 | lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"] 686 | test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] 687 | 688 | [[package]] 689 | name = "sphinx-pyproject" 690 | version = "0.1.0" 691 | description = "Move some of your Sphinx configuration into pyproject.toml" 692 | category = "dev" 693 | optional = false 694 | python-versions = ">=3.6" 695 | 696 | [package.dependencies] 697 | dom-toml = ">=0.3.0" 698 | domdf-python-tools = ">=2.7.0" 699 | 700 | [[package]] 701 | name = "sphinx-rtd-theme" 702 | version = "1.0.0" 703 | description = "Read the Docs theme for Sphinx" 704 | category = "dev" 705 | optional = false 706 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 707 | 708 | [package.dependencies] 709 | docutils = "<0.18" 710 | sphinx = ">=1.6" 711 | 712 | [package.extras] 713 | dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] 714 | 715 | [[package]] 716 | name = "sphinxcontrib-applehelp" 717 | version = "1.0.2" 718 | description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" 719 | category = "dev" 720 | optional = false 721 | python-versions = ">=3.5" 722 | 723 | [package.extras] 724 | lint = ["flake8", "mypy", "docutils-stubs"] 725 | test = ["pytest"] 726 | 727 | [[package]] 728 | name = "sphinxcontrib-devhelp" 729 | version = "1.0.2" 730 | description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." 731 | category = "dev" 732 | optional = false 733 | python-versions = ">=3.5" 734 | 735 | [package.extras] 736 | lint = ["flake8", "mypy", "docutils-stubs"] 737 | test = ["pytest"] 738 | 739 | [[package]] 740 | name = "sphinxcontrib-htmlhelp" 741 | version = "2.0.0" 742 | description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" 743 | category = "dev" 744 | optional = false 745 | python-versions = ">=3.6" 746 | 747 | [package.extras] 748 | lint = ["flake8", "mypy", "docutils-stubs"] 749 | test = ["pytest", "html5lib"] 750 | 751 | [[package]] 752 | name = "sphinxcontrib-jsmath" 753 | version = "1.0.1" 754 | description = "A sphinx extension which renders display math in HTML via JavaScript" 755 | category = "dev" 756 | optional = false 757 | python-versions = ">=3.5" 758 | 759 | [package.extras] 760 | test = ["pytest", "flake8", "mypy"] 761 | 762 | [[package]] 763 | name = "sphinxcontrib-qthelp" 764 | version = "1.0.3" 765 | description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." 766 | category = "dev" 767 | optional = false 768 | python-versions = ">=3.5" 769 | 770 | [package.extras] 771 | lint = ["flake8", "mypy", "docutils-stubs"] 772 | test = ["pytest"] 773 | 774 | [[package]] 775 | name = "sphinxcontrib-serializinghtml" 776 | version = "1.1.5" 777 | description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." 778 | category = "dev" 779 | optional = false 780 | python-versions = ">=3.5" 781 | 782 | [package.extras] 783 | lint = ["flake8", "mypy", "docutils-stubs"] 784 | test = ["pytest"] 785 | 786 | [[package]] 787 | name = "taskipy" 788 | version = "1.10.1" 789 | description = "tasks runner for python projects" 790 | category = "dev" 791 | optional = false 792 | python-versions = ">=3.6,<4.0" 793 | 794 | [package.dependencies] 795 | colorama = ">=0.4.4,<0.5.0" 796 | mslex = {version = ">=0.3.0,<0.4.0", markers = "sys_platform == \"win32\""} 797 | psutil = ">=5.7.2,<6.0.0" 798 | tomli = ">=1.2.3,<2.0.0" 799 | 800 | [[package]] 801 | name = "testfixtures" 802 | version = "6.18.5" 803 | description = "A collection of helpers and mock objects for unit tests and doc tests." 804 | category = "dev" 805 | optional = false 806 | python-versions = "*" 807 | 808 | [package.extras] 809 | build = ["setuptools-git", "wheel", "twine"] 810 | docs = ["sphinx", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] 811 | test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] 812 | 813 | [[package]] 814 | name = "toml" 815 | version = "0.10.2" 816 | description = "Python Library for Tom's Obvious, Minimal Language" 817 | category = "dev" 818 | optional = false 819 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 820 | 821 | [[package]] 822 | name = "tomli" 823 | version = "1.2.3" 824 | description = "A lil' TOML parser" 825 | category = "dev" 826 | optional = false 827 | python-versions = ">=3.6" 828 | 829 | [[package]] 830 | name = "typing-extensions" 831 | version = "4.2.0" 832 | description = "Backported and Experimental Type Hints for Python 3.7+" 833 | category = "dev" 834 | optional = false 835 | python-versions = ">=3.7" 836 | 837 | [[package]] 838 | name = "urllib3" 839 | version = "1.26.9" 840 | description = "HTTP library with thread-safe connection pooling, file post, and more." 841 | category = "dev" 842 | optional = false 843 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 844 | 845 | [package.extras] 846 | brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] 847 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 848 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 849 | 850 | [[package]] 851 | name = "virtualenv" 852 | version = "20.14.1" 853 | description = "Virtual Python Environment builder" 854 | category = "dev" 855 | optional = false 856 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 857 | 858 | [package.dependencies] 859 | distlib = ">=0.3.1,<1" 860 | filelock = ">=3.2,<4" 861 | platformdirs = ">=2,<3" 862 | six = ">=1.9.0,<2" 863 | 864 | [package.extras] 865 | docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] 866 | testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] 867 | 868 | [metadata] 869 | lock-version = "1.1" 870 | python-versions = "^3.10" 871 | content-hash = "f731cfbcc6536561a73fd9c632d7f22d042771113491c1ce93b3da1011b643f7" 872 | 873 | [metadata.files] 874 | alabaster = [ 875 | {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, 876 | {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, 877 | ] 878 | atomicwrites = [ 879 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 880 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 881 | ] 882 | attrs = [ 883 | {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, 884 | {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, 885 | ] 886 | babel = [ 887 | {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, 888 | {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, 889 | ] 890 | black = [ 891 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, 892 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, 893 | {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, 894 | {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, 895 | {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, 896 | {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, 897 | {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, 898 | {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, 899 | {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, 900 | {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, 901 | {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, 902 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, 903 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, 904 | {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, 905 | {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, 906 | {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, 907 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, 908 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, 909 | {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, 910 | {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, 911 | {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, 912 | {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, 913 | {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, 914 | ] 915 | certifi = [ 916 | {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, 917 | {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, 918 | ] 919 | cfgv = [ 920 | {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, 921 | {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, 922 | ] 923 | charset-normalizer = [ 924 | {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, 925 | {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, 926 | ] 927 | click = [ 928 | {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, 929 | {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, 930 | ] 931 | colorama = [ 932 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 933 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 934 | ] 935 | coverage = [ 936 | {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, 937 | {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, 938 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, 939 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, 940 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, 941 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, 942 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, 943 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, 944 | {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, 945 | {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, 946 | {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, 947 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, 948 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, 949 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, 950 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, 951 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, 952 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, 953 | {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, 954 | {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, 955 | {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, 956 | {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, 957 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, 958 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, 959 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, 960 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, 961 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, 962 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, 963 | {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, 964 | {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, 965 | {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, 966 | {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, 967 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, 968 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, 969 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, 970 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, 971 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, 972 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, 973 | {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, 974 | {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, 975 | {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, 976 | {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, 977 | ] 978 | distlib = [ 979 | {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, 980 | {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, 981 | ] 982 | docutils = [ 983 | {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, 984 | {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, 985 | ] 986 | dom-toml = [ 987 | {file = "dom_toml-0.5.1.post1-py3-none-any.whl", hash = "sha256:492293ded75d864365ac15f10d3796c1b3b2e3bb26e949e19f16781089f8a75f"}, 988 | {file = "dom_toml-0.5.1.post1.tar.gz", hash = "sha256:5fe4c5d8925528d509be41b878aeb8c24f2d3cc2e85c37d3d451542965138f3b"}, 989 | ] 990 | domdf-python-tools = [ 991 | {file = "domdf-python-tools-3.2.2.post1.tar.gz", hash = "sha256:fef90a0109b284424b14f9513e3b543f68feb1d48beddde435928e0f05f4664e"}, 992 | {file = "domdf_python_tools-3.2.2.post1-py3-none-any.whl", hash = "sha256:70a9771dea6f5aa37779d2a86d4abaf63f8fa305e3313a53f71f45b8c8c5fd08"}, 993 | ] 994 | eradicate = [ 995 | {file = "eradicate-2.1.0-py3-none-any.whl", hash = "sha256:8bfaca181db9227dc88bdbce4d051a9627604c2243e7d85324f6d6ce0fd08bb2"}, 996 | {file = "eradicate-2.1.0.tar.gz", hash = "sha256:aac7384ab25b1bf21c4c012de9b4bf8398945a14c98c911545b2ea50ab558014"}, 997 | ] 998 | filelock = [ 999 | {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, 1000 | {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, 1001 | ] 1002 | flake8 = [ 1003 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, 1004 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, 1005 | ] 1006 | flake8-bugbear = [ 1007 | {file = "flake8-bugbear-22.3.23.tar.gz", hash = "sha256:e0dc2a36474490d5b1a2d57f9e4ef570abc09f07cbb712b29802e28a2367ff19"}, 1008 | {file = "flake8_bugbear-22.3.23-py3-none-any.whl", hash = "sha256:ec5ec92195720cee1589315416b844ffa5e82f73a78e65329e8055322df1e939"}, 1009 | ] 1010 | flake8-builtins = [ 1011 | {file = "flake8-builtins-1.5.3.tar.gz", hash = "sha256:09998853b2405e98e61d2ff3027c47033adbdc17f9fe44ca58443d876eb00f3b"}, 1012 | {file = "flake8_builtins-1.5.3-py2.py3-none-any.whl", hash = "sha256:7706babee43879320376861897e5d1468e396a40b8918ed7bccf70e5f90b8687"}, 1013 | ] 1014 | flake8-eradicate = [ 1015 | {file = "flake8-eradicate-1.2.0.tar.gz", hash = "sha256:acaa1b6839ff00d284b805c432fdfa6047262bd15a5504ec945797e87b4de1fa"}, 1016 | {file = "flake8_eradicate-1.2.0-py3-none-any.whl", hash = "sha256:51dc660d0c1c1ed93af0f813540bbbf72ab2d3466c14e3f3bac371c618b6042f"}, 1017 | ] 1018 | flake8-isort = [ 1019 | {file = "flake8-isort-4.1.1.tar.gz", hash = "sha256:d814304ab70e6e58859bc5c3e221e2e6e71c958e7005239202fee19c24f82717"}, 1020 | {file = "flake8_isort-4.1.1-py3-none-any.whl", hash = "sha256:c4e8b6dcb7be9b71a02e6e5d4196cefcef0f3447be51e82730fb336fff164949"}, 1021 | ] 1022 | flake8-plugin-utils = [ 1023 | {file = "flake8-plugin-utils-1.3.2.tar.gz", hash = "sha256:20fa2a8ca2decac50116edb42e6af0a1253ef639ad79941249b840531889c65a"}, 1024 | {file = "flake8_plugin_utils-1.3.2-py3-none-any.whl", hash = "sha256:1fe43e3e9acf3a7c0f6b88f5338cad37044d2f156c43cb6b080b5f9da8a76f06"}, 1025 | ] 1026 | flake8-polyfill = [ 1027 | {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, 1028 | {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, 1029 | ] 1030 | flake8-pytest-style = [ 1031 | {file = "flake8-pytest-style-1.6.0.tar.gz", hash = "sha256:c1175713e9e11b78cd1a035ed0bca0d1e41d09c4af329a952750b61d4194ddac"}, 1032 | {file = "flake8_pytest_style-1.6.0-py3-none-any.whl", hash = "sha256:5fedb371a950e9fe0e0e6bfc854be7d99151271208f34cd2cc517681ece27780"}, 1033 | ] 1034 | flake8-unused-arguments = [ 1035 | {file = "flake8-unused-arguments-0.0.9.tar.gz", hash = "sha256:80e437b126a441ba048dfc9f01987fbec1ea8521e65c00681aecdf4c466fa27b"}, 1036 | {file = "flake8_unused_arguments-0.0.9-py3-none-any.whl", hash = "sha256:b3b02aa5379e2edc7a3fc98e4bd12b2febf0573131a12fb7d698c04c0a8effda"}, 1037 | ] 1038 | identify = [ 1039 | {file = "identify-2.4.12-py2.py3-none-any.whl", hash = "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323"}, 1040 | {file = "identify-2.4.12.tar.gz", hash = "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17"}, 1041 | ] 1042 | idna = [ 1043 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, 1044 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, 1045 | ] 1046 | imagesize = [ 1047 | {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, 1048 | {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, 1049 | ] 1050 | iniconfig = [ 1051 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 1052 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 1053 | ] 1054 | isort = [ 1055 | {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, 1056 | {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, 1057 | ] 1058 | jinja2 = [ 1059 | {file = "Jinja2-3.1.1-py3-none-any.whl", hash = "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119"}, 1060 | {file = "Jinja2-3.1.1.tar.gz", hash = "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9"}, 1061 | ] 1062 | markupsafe = [ 1063 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, 1064 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, 1065 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, 1066 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, 1067 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, 1068 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, 1069 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, 1070 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, 1071 | {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, 1072 | {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, 1073 | {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, 1074 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, 1075 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, 1076 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, 1077 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, 1078 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, 1079 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, 1080 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, 1081 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, 1082 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, 1083 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, 1084 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, 1085 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, 1086 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, 1087 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, 1088 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, 1089 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, 1090 | {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, 1091 | {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, 1092 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, 1093 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, 1094 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, 1095 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, 1096 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, 1097 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, 1098 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, 1099 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, 1100 | {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, 1101 | {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, 1102 | {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, 1103 | ] 1104 | mccabe = [ 1105 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 1106 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 1107 | ] 1108 | mslex = [ 1109 | {file = "mslex-0.3.0-py2.py3-none-any.whl", hash = "sha256:380cb14abf8fabf40e56df5c8b21a6d533dc5cbdcfe42406bbf08dda8f42e42a"}, 1110 | {file = "mslex-0.3.0.tar.gz", hash = "sha256:4a1ac3f25025cad78ad2fe499dd16d42759f7a3801645399cce5c404415daa97"}, 1111 | ] 1112 | mypy = [ 1113 | {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, 1114 | {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, 1115 | {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"}, 1116 | {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"}, 1117 | {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"}, 1118 | {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"}, 1119 | {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"}, 1120 | {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"}, 1121 | {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"}, 1122 | {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"}, 1123 | {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"}, 1124 | {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"}, 1125 | {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"}, 1126 | {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"}, 1127 | {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"}, 1128 | {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"}, 1129 | {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"}, 1130 | {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"}, 1131 | {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"}, 1132 | {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"}, 1133 | {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"}, 1134 | {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"}, 1135 | {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, 1136 | ] 1137 | mypy-extensions = [ 1138 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 1139 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 1140 | ] 1141 | natsort = [ 1142 | {file = "natsort-8.1.0-py3-none-any.whl", hash = "sha256:f59988d2f24e77b6b56f8a8f882d5df6b3b637e09e075abc67b486d59fba1a4b"}, 1143 | {file = "natsort-8.1.0.tar.gz", hash = "sha256:c7c1f3f27c375719a4dfcab353909fe39f26c2032a062a8c80cc844eaaca0445"}, 1144 | ] 1145 | nodeenv = [ 1146 | {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, 1147 | {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, 1148 | ] 1149 | packaging = [ 1150 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 1151 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 1152 | ] 1153 | pathspec = [ 1154 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 1155 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 1156 | ] 1157 | pep8-naming = [ 1158 | {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"}, 1159 | {file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"}, 1160 | ] 1161 | platformdirs = [ 1162 | {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, 1163 | {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, 1164 | ] 1165 | pluggy = [ 1166 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 1167 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 1168 | ] 1169 | pre-commit = [ 1170 | {file = "pre_commit-2.18.1-py2.py3-none-any.whl", hash = "sha256:02226e69564ebca1a070bd1f046af866aa1c318dbc430027c50ab832ed2b73f2"}, 1171 | {file = "pre_commit-2.18.1.tar.gz", hash = "sha256:5d445ee1fa8738d506881c5d84f83c62bb5be6b2838e32207433647e8e5ebe10"}, 1172 | ] 1173 | psutil = [ 1174 | {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b"}, 1175 | {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618"}, 1176 | {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2"}, 1177 | {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd"}, 1178 | {file = "psutil-5.9.0-cp27-none-win32.whl", hash = "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3"}, 1179 | {file = "psutil-5.9.0-cp27-none-win_amd64.whl", hash = "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c"}, 1180 | {file = "psutil-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492"}, 1181 | {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"}, 1182 | {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2"}, 1183 | {file = "psutil-5.9.0-cp310-cp310-win32.whl", hash = "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d"}, 1184 | {file = "psutil-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b"}, 1185 | {file = "psutil-5.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0"}, 1186 | {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce"}, 1187 | {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5"}, 1188 | {file = "psutil-5.9.0-cp37-cp37m-win32.whl", hash = "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9"}, 1189 | {file = "psutil-5.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4"}, 1190 | {file = "psutil-5.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2"}, 1191 | {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d"}, 1192 | {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a"}, 1193 | {file = "psutil-5.9.0-cp38-cp38-win32.whl", hash = "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666"}, 1194 | {file = "psutil-5.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841"}, 1195 | {file = "psutil-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf"}, 1196 | {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07"}, 1197 | {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d"}, 1198 | {file = "psutil-5.9.0-cp39-cp39-win32.whl", hash = "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845"}, 1199 | {file = "psutil-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3"}, 1200 | {file = "psutil-5.9.0.tar.gz", hash = "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25"}, 1201 | ] 1202 | py = [ 1203 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 1204 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 1205 | ] 1206 | pycodestyle = [ 1207 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, 1208 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, 1209 | ] 1210 | pyflakes = [ 1211 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, 1212 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, 1213 | ] 1214 | pygments = [ 1215 | {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, 1216 | {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, 1217 | ] 1218 | pyparsing = [ 1219 | {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, 1220 | {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, 1221 | ] 1222 | pytest = [ 1223 | {file = "pytest-7.1.1-py3-none-any.whl", hash = "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"}, 1224 | {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, 1225 | ] 1226 | pytest-cov = [ 1227 | {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, 1228 | {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, 1229 | ] 1230 | pytest-mock = [ 1231 | {file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"}, 1232 | {file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"}, 1233 | ] 1234 | pytz = [ 1235 | {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, 1236 | {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, 1237 | ] 1238 | pyyaml = [ 1239 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, 1240 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, 1241 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, 1242 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, 1243 | {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"}, 1244 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, 1245 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, 1246 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, 1247 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, 1248 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, 1249 | {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"}, 1250 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, 1251 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, 1252 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, 1253 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, 1254 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, 1255 | {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"}, 1256 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, 1257 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, 1258 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, 1259 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, 1260 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, 1261 | {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"}, 1262 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, 1263 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, 1264 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, 1265 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, 1266 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, 1267 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, 1268 | {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"}, 1269 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, 1270 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, 1271 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, 1272 | ] 1273 | requests = [ 1274 | {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, 1275 | {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, 1276 | ] 1277 | six = [ 1278 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1279 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1280 | ] 1281 | snowballstemmer = [ 1282 | {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, 1283 | {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, 1284 | ] 1285 | sphinx = [ 1286 | {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, 1287 | {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, 1288 | ] 1289 | sphinx-pyproject = [ 1290 | {file = "sphinx_pyproject-0.1.0-py3-none-any.whl", hash = "sha256:aaa974eb1bf9456c4bf9f97c9e1eb19469e337b5d30271f163085014ef7a8365"}, 1291 | {file = "sphinx_pyproject-0.1.0.tar.gz", hash = "sha256:c2525c3c473a771e95fca4691da0e35aebcc459ff618a7912d9b57bc995eef3d"}, 1292 | ] 1293 | sphinx-rtd-theme = [ 1294 | {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, 1295 | {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, 1296 | ] 1297 | sphinxcontrib-applehelp = [ 1298 | {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, 1299 | {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, 1300 | ] 1301 | sphinxcontrib-devhelp = [ 1302 | {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, 1303 | {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, 1304 | ] 1305 | sphinxcontrib-htmlhelp = [ 1306 | {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, 1307 | {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, 1308 | ] 1309 | sphinxcontrib-jsmath = [ 1310 | {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, 1311 | {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, 1312 | ] 1313 | sphinxcontrib-qthelp = [ 1314 | {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, 1315 | {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, 1316 | ] 1317 | sphinxcontrib-serializinghtml = [ 1318 | {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, 1319 | {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, 1320 | ] 1321 | taskipy = [ 1322 | {file = "taskipy-1.10.1-py3-none-any.whl", hash = "sha256:9b38333654da487b6d16de6fa330b7629d1935d1e74819ba4c5f17a1c372d37b"}, 1323 | {file = "taskipy-1.10.1.tar.gz", hash = "sha256:6fa0b11c43d103e376063e90be31d87b435aad50fb7dc1c9a2de9b60a85015ed"}, 1324 | ] 1325 | testfixtures = [ 1326 | {file = "testfixtures-6.18.5-py2.py3-none-any.whl", hash = "sha256:7de200e24f50a4a5d6da7019fb1197aaf5abd475efb2ec2422fdcf2f2eb98c1d"}, 1327 | {file = "testfixtures-6.18.5.tar.gz", hash = "sha256:02dae883f567f5b70fd3ad3c9eefb95912e78ac90be6c7444b5e2f46bf572c84"}, 1328 | ] 1329 | toml = [ 1330 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1331 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1332 | ] 1333 | tomli = [ 1334 | {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, 1335 | {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, 1336 | ] 1337 | typing-extensions = [ 1338 | {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, 1339 | {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, 1340 | ] 1341 | urllib3 = [ 1342 | {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, 1343 | {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, 1344 | ] 1345 | virtualenv = [ 1346 | {file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"}, 1347 | {file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"}, 1348 | ] 1349 | -------------------------------------------------------------------------------- /poetry.toml: -------------------------------------------------------------------------------- 1 | [virtualenvs] 2 | in-project = true 3 | path = ".venv" 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "python-template" 3 | version = "0.1.0" 4 | description = "Python Project の Template" 5 | authors = ["jDBTISK"] 6 | readme = "README.md" 7 | repository = "https://github.com/jDBTISK/python-project-template" 8 | 9 | [project] 10 | name = "python-template" 11 | version = "0.1.0" 12 | description = "Python Project の Template" 13 | readme = "README.md" 14 | 15 | [[project.authors]] 16 | name = "jDBTISK" 17 | 18 | [tool.poetry.dependencies] 19 | python = "^3.10" 20 | 21 | [tool.poetry.dev-dependencies] 22 | pre-commit = "^2.18.1" 23 | taskipy = "^1.10.1" 24 | black = "^22.3.0" 25 | mypy = "^0.942" 26 | isort = "^5.10.1" 27 | flake8 = "^4.0.1" 28 | flake8-isort = "^4.1.1" 29 | flake8-bugbear = "^22.3.23" 30 | flake8-builtins = "^1.5.3" 31 | flake8-eradicate = "^1.2.0" 32 | flake8-pytest-style = "^1.6.0" 33 | flake8-unused-arguments = "^0.0.9" 34 | pep8-naming = "^0.12.1" 35 | pytest = "^7.1.1" 36 | pytest-mock = "^3.7.0" 37 | pytest-cov = "^3.0.0" 38 | Sphinx = "^4.5.0" 39 | sphinx-rtd-theme = "^1.0.0" 40 | sphinx-pyproject = "^0.1.0" 41 | 42 | [build-system] 43 | requires = ["poetry-core>=1.0.0"] 44 | build-backend = "poetry.core.masonry.api" 45 | 46 | [tool.taskipy.tasks] 47 | test = "pytest -s -vv --cov=. --cov-branch --cov-report=html" 48 | fmt = "task fmt-black && task fmt-isort" 49 | fmt-black = "black src tests" 50 | fmt-isort = "isort src tests" 51 | lint = "task lint-black && task lint-flake8 && task lint-mypy" 52 | lint-flake8 = "flake8 src tests" 53 | lint-mypy = "mypy src tests" 54 | lint-black = "black --check src tests" 55 | docs = "sphinx-apidoc -F -o docs/source src && sphinx-build docs/source docs/build" 56 | 57 | [tool.mypy] 58 | show_error_context = true 59 | show_column_numbers = true 60 | ignore_missing_imports = true 61 | disallow_untyped_defs = true 62 | no_implicit_optional = true 63 | warn_return_any = true 64 | warn_unused_ignores = true 65 | warn_redundant_casts = true 66 | 67 | [tool.black] 68 | line-length = 79 69 | 70 | [tool.isort] 71 | profile = "black" 72 | line_length = 79 73 | 74 | [tool.sphinx-pyproject] 75 | project = "python-template" 76 | copyright = "2022, jDBTISK" 77 | language = "en" 78 | package_root = "python-template" 79 | html_theme = "sphinx_rtd_theme" 80 | todo_include_todos = true 81 | templates_path = ["_templates"] 82 | html_static_path = ["_static"] 83 | extensions = [ 84 | "sphinx.ext.autodoc", 85 | "sphinx.ext.viewcode", 86 | "sphinx.ext.todo", 87 | "sphinx.ext.napoleon", 88 | ] 89 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jDBTISK/python-project-template/afcc725cea2ac461c0e7742796cd2619ba6bc9c8/src/__init__.py -------------------------------------------------------------------------------- /src/sample.py: -------------------------------------------------------------------------------- 1 | def add(x: int, y: int) -> int: 2 | """ 3 | 整数の加算結果を返却 4 | 5 | Parameters 6 | ---------- 7 | x : int 8 | 加算対象整数1 9 | y : int 10 | 加算対象整数2 11 | 12 | Returns 13 | ------- 14 | int 15 | 加算結果整数 16 | """ 17 | return x + y 18 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jDBTISK/python-project-template/afcc725cea2ac461c0e7742796cd2619ba6bc9c8/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append( 5 | os.path.abspath(f"{os.path.dirname(os.path.abspath(__file__))}/../src/") 6 | ) 7 | -------------------------------------------------------------------------------- /tests/test_sample.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from sample import add 4 | 5 | 6 | @pytest.mark.parametrize(("x", "y", "correct"), [(1, 1, 2), (5, -1, 4)]) 7 | def test_add(x: int, y: int, correct: int) -> None: 8 | """ 9 | 加算処理のテスト 10 | 11 | Parameters 12 | ---------- 13 | x : int 14 | y : int 15 | correct : int 16 | 加算結果の正解値 17 | """ 18 | assert add(x, y) == correct 19 | --------------------------------------------------------------------------------