From 2b7653c93229ba66683570f3b891d226be6b558b Mon Sep 17 00:00:00 2001 From: alex-smile <443677891@qq.com> Date: Wed, 29 Nov 2023 18:10:56 +0800 Subject: [PATCH] add examples (#134) --- .github/workflows/apigw-manager.yml | 49 +- .github/workflows/bkapi-client-core.yml | 43 +- .pre-commit-config.yaml | 44 +- sdks/apigw-manager/.flake8 | 16 - sdks/apigw-manager/.isort.cfg | 8 - sdks/apigw-manager/.pre-commit-config.yaml | 23 - sdks/apigw-manager/CHANGE.md | 13 +- sdks/apigw-manager/Dockerfile | 6 +- sdks/apigw-manager/Makefile | 4 + sdks/apigw-manager/README.md | 295 ++-- sdks/apigw-manager/README.rst | 336 +++-- .../apigw-manager => bin/apigw-manager.sh} | 3 +- sdks/apigw-manager/bin/functions.sh | 94 ++ sdks/apigw-manager/bin/sync-apigateway.sh | 27 + sdks/apigw-manager/definition.yaml | 80 - sdks/apigw-manager/demo/bin/sync-apigateway | 102 -- sdks/apigw-manager/demo/settings.py | 14 +- sdks/apigw-manager/demo/urls.py | 9 +- sdks/apigw-manager/demo/views.py | 6 +- .../docs/sync-apigateway-with-django.md | 138 ++ .../docs/sync-apigateway-with-docker.md | 268 ++++ .../examples/chart/use-configmap/Chart.yaml | 6 + .../examples/chart/use-configmap/README.md | 5 + .../support-files/apidocs/en/anything.md | 29 + .../support-files/apidocs/zh/anything.md | 29 + .../support-files/bin/sync-apigateway.sh | 29 + .../files/support-files/definition.yaml | 41 + .../files/support-files/resources.yaml | 34 + .../use-configmap/templates/_helpers.tpl | 65 + .../templates/sync-apigateway-configmap.yaml | 15 + .../templates/sync-apigateway-job.yaml | 39 + .../examples/chart/use-configmap/values.yaml | 25 + .../chart/use-custom-docker-image/README.md | 10 + .../bk-demo-chart/Chart.yaml | 6 + .../bk-demo-chart/templates/_helpers.tpl | 65 + .../templates/sync-apigateway-job.yaml | 26 + .../bk-demo-chart/values.yaml | 12 + .../my-apigw-manager/Dockerfile | 3 + .../support-files/apidocs/en/anything.md | 29 + .../support-files/apidocs/zh/anything.md | 29 + .../support-files/bin/sync-apigateway.sh | 29 + .../support-files/definition.yaml | 41 + .../support-files/resources.yaml | 34 + .../django/use-custom-script/README.md | 8 + .../support-files/apidocs/en/anything.md | 29 + .../support-files/apidocs/zh/anything.md | 29 + .../support-files/bin/sync-apigateway.sh | 26 + .../support-files/definition.yaml | 41 + .../support-files/resources.yaml | 34 + sdks/apigw-manager/mypy.ini | 7 - sdks/apigw-manager/poetry.lock | 1332 +++++++++-------- sdks/apigw-manager/pyproject.toml | 147 +- sdks/apigw-manager/requirements_tox.txt | 100 ++ .../src/apigw_manager/apigw/authentication.py | 1 - .../src/apigw_manager/apigw/command.py | 9 +- .../src/apigw_manager/apigw/decorators.py | 1 - .../src/apigw_manager/apigw/helper.py | 1 - .../src/apigw_manager/apigw/k8s_helper.py | 3 - .../management/commands/add_related_apps.py | 8 +- .../commands/apply_apigw_permissions.py | 14 +- .../create_version_and_release_apigw.py | 4 +- .../commands/fetch_apigw_public_key.py | 1 - .../commands/fetch_esb_public_key.py | 4 +- .../management/commands/sync_apigw_config.py | 4 +- .../commands/sync_apigw_strategies.py | 2 +- .../commands/sync_resource_docs_by_archive.py | 4 +- .../src/apigw_manager/apigw/providers.py | 8 +- .../src/apigw_manager/apigw/utils.py | 3 +- .../src/apigw_manager/core/exceptions.py | 4 +- .../src/apigw_manager/core/fetch.py | 2 +- .../src/apigw_manager/core/handler.py | 4 +- .../src/apigw_manager/core/sync.py | 2 +- .../src/apigw_manager/core/utils.py | 3 +- .../commands/test_apply_apigw_permissions.py | 1 - .../test_create_version_and_release_apigw.py | 17 +- .../commands/test_sync_apigw_resources.py | 2 +- .../apigw/test_authentication.py | 14 +- .../tests/apigw_manager/apigw/test_command.py | 4 +- .../apigw_manager/apigw/test_decorators.py | 2 +- .../tests/apigw_manager/apigw/test_helper.py | 20 +- .../apigw_manager/apigw/test_k8s_helper.py | 2 +- .../apigw_manager/apigw/test_providers.py | 2 +- .../tests/apigw_manager/apigw/test_utils.py | 4 +- .../tests/apigw_manager/core/conftest.py | 14 +- .../tests/apigw_manager/core/test_hander.py | 20 +- .../tests/apigw_manager/core/test_utils.py | 6 +- sdks/apigw-manager/tests/conftest.py | 28 +- sdks/apigw-manager/tests/demo/test_views.py | 4 +- sdks/apigw-manager/tox.ini | 1 - .../bkapi-client-core/.pre-commit-config.yaml | 42 - .../bkapi_client_core/apigateway/client.py | 4 +- .../apigateway/django_helper.py | 4 +- .../bkapi_client_core/auth.py | 4 +- .../bkapi_client_core/base.py | 20 +- .../bkapi_client_core/client.py | 8 +- .../bkapi_client_core/config.py | 16 +- .../bkapi_client_core/django_helper.py | 10 +- .../bkapi_client_core/esb/client.py | 4 +- .../bkapi_client_core/esb/django_helper.py | 4 +- .../bkapi_client_core/exceptions.py | 2 +- .../bkapi_client_core/prometheus.py | 15 +- .../bkapi_client_core/property.py | 4 +- .../bkapi_client_core/session.py | 11 +- .../bkapi_client_core/utils.py | 4 +- sdks/bkapi-client-core/poetry.lock | 825 +++------- sdks/bkapi-client-core/pyproject.toml | 156 +- .../tests/apigateway/test_client.py | 4 +- .../tests/apigateway/test_django_helper.py | 2 +- .../tests/esb/test_client.py | 10 +- .../tests/esb/test_django_helper.py | 2 +- sdks/bkapi-client-core/tests/test_auth.py | 2 +- sdks/bkapi-client-core/tests/test_base.py | 20 +- sdks/bkapi-client-core/tests/test_client.py | 24 +- sdks/bkapi-client-core/tests/test_config.py | 6 +- .../tests/test_django_helper.py | 8 +- .../tests/test_exceptions.py | 8 +- .../tests/test_prometheus.py | 15 +- sdks/bkapi-client-core/tests/test_property.py | 4 +- sdks/bkapi-client-core/tests/test_session.py | 6 +- sdks/bkapi-client-core/tests/test_utils.py | 10 +- 120 files changed, 3271 insertions(+), 2138 deletions(-) delete mode 100644 sdks/apigw-manager/.flake8 delete mode 100644 sdks/apigw-manager/.isort.cfg delete mode 100644 sdks/apigw-manager/.pre-commit-config.yaml rename sdks/apigw-manager/{demo/bin/apigw-manager => bin/apigw-manager.sh} (52%) create mode 100755 sdks/apigw-manager/bin/functions.sh create mode 100755 sdks/apigw-manager/bin/sync-apigateway.sh delete mode 100644 sdks/apigw-manager/definition.yaml delete mode 100755 sdks/apigw-manager/demo/bin/sync-apigateway create mode 100644 sdks/apigw-manager/docs/sync-apigateway-with-django.md create mode 100644 sdks/apigw-manager/docs/sync-apigateway-with-docker.md create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/Chart.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/README.md create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/en/anything.md create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/zh/anything.md create mode 100755 sdks/apigw-manager/examples/chart/use-configmap/files/support-files/bin/sync-apigateway.sh create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/files/support-files/definition.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/files/support-files/resources.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/templates/_helpers.tpl create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-configmap.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-job.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-configmap/values.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/README.md create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/Chart.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/_helpers.tpl create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/sync-apigateway-job.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/values.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/Dockerfile create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/en/anything.md create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/zh/anything.md create mode 100755 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/bin/sync-apigateway.sh create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/definition.yaml create mode 100644 sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/resources.yaml create mode 100644 sdks/apigw-manager/examples/django/use-custom-script/README.md create mode 100644 sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/en/anything.md create mode 100644 sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/zh/anything.md create mode 100755 sdks/apigw-manager/examples/django/use-custom-script/support-files/bin/sync-apigateway.sh create mode 100644 sdks/apigw-manager/examples/django/use-custom-script/support-files/definition.yaml create mode 100644 sdks/apigw-manager/examples/django/use-custom-script/support-files/resources.yaml delete mode 100644 sdks/apigw-manager/mypy.ini create mode 100644 sdks/apigw-manager/requirements_tox.txt delete mode 100644 sdks/bkapi-client-core/.pre-commit-config.yaml diff --git a/.github/workflows/apigw-manager.yml b/.github/workflows/apigw-manager.yml index c9b0113e..518a1e1b 100644 --- a/.github/workflows/apigw-manager.yml +++ b/.github/workflows/apigw-manager.yml @@ -1,3 +1,5 @@ +name: apigw-manager + on: push: branches: @@ -9,34 +11,31 @@ on: - master paths: - "sdks/apigw-manager/**" -name: apigw-manager + jobs: test: + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - python-version: [3.6, 3.7] - os: [ubuntu-18.04, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} + python-version: ["3.6", "3.7"] + os: [ubuntu-20.04, macos-latest, windows-latest] steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Set up Poetry - uses: abatilo/actions-poetry@v2.1.0 - with: - poetry-version: 1.1.15 - - name: Install dependencies - working-directory: sdks/apigw-manager - run: | - poetry export -f requirements.txt --without-hashes -E demo --dev --output requirements.txt - python -m pip install --upgrade pip - python -m pip install . 'tox-gh-actions==2.12.0' -r requirements.txt - - name: Test with tox - working-directory: sdks/apigw-manager - run: tox + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: 'sdks/apigw-manager/requirements_tox.txt' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install . 'tox-gh-actions==2.12.0' -r requirements_tox.txt + working-directory: sdks/apigw-manager + + - name: Test with tox + run: tox + working-directory: sdks/apigw-manager diff --git a/.github/workflows/bkapi-client-core.yml b/.github/workflows/bkapi-client-core.yml index a7410903..496d2e2a 100644 --- a/.github/workflows/bkapi-client-core.yml +++ b/.github/workflows/bkapi-client-core.yml @@ -1,3 +1,5 @@ +name: bkapi-client-core + on: push: branches: @@ -9,28 +11,31 @@ on: - "master" paths: - "sdks/bkapi-client-core/**" -name: bkapi-client-core + jobs: test: + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - python-version: [2.7, 3.7] - os: [ubuntu-18.04, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} + python-version: ["3.6", "3.7"] + os: [ubuntu-20.04, macos-latest, windows-latest] + steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install 'tox==3.23.0' 'tox-gh-actions==2.12.0' - - name: Test with tox - working-directory: sdks/bkapi-client-core - run: tox + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: 'sdks/bkapi-client-core/requirements_tox.txt' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install 'tox==3.23.0' 'tox-gh-actions==2.12.0' + + - name: Test with tox + run: tox + working-directory: sdks/bkapi-client-core diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77b71e1b..40669b94 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,4 +45,46 @@ repos: types: [python] pass_filenames: false entry: bash -c "cd sdks/paas-service && poetry run mypy . --config-file=./pyproject.toml" - files: '^sdks/paas-service/' \ No newline at end of file + files: '^sdks/paas-service/' + # sdk bkapi-client-core + - repo: local + hooks: + - id: format + name: run ruff-formatter for "bkapi-client-core" + language: python + types: [python] + entry: bash -c 'cd sdks/bkapi-client-core/ && ruff format --config=pyproject.toml --force-exclude .' + files: sdks/bkapi-client-core/ + - id: ruff + name: run ruff for "bkapi-client-core" + language: python + types: [python] + entry: bash -c 'cd sdks/bkapi-client-core/ && ruff --config=pyproject.toml --force-exclude --fix .' + files: sdks/bkapi-client-core/ + - id: mypy + name: run mypy for "bkapi-client-core" + language: python + types: [python] + entry: mypy --config-file=sdks/bkapi-client-core/pyproject.toml + files: sdks/bkapi-client-core/ + # sdk apigw-manager + - repo: local + hooks: + - id: format + name: run ruff-formatter for "apigw-manager" + language: python + types: [python] + entry: bash -c 'cd sdks/apigw-manager/ && ruff format --config=pyproject.toml --force-exclude .' + files: sdks/apigw-manager/ + - id: ruff + name: run ruff for "apigw-manager" + language: python + types: [python] + entry: bash -c 'cd sdks/apigw-manager/ && ruff --config=pyproject.toml --force-exclude --fix .' + files: sdks/apigw-manager/ + - id: mypy + name: run mypy for "apigw-manager" + language: python + types: [python] + entry: mypy --config-file=sdks/apigw-manager/pyproject.toml + files: sdks/apigw-manager/ \ No newline at end of file diff --git a/sdks/apigw-manager/.flake8 b/sdks/apigw-manager/.flake8 deleted file mode 100644 index 363eb596..00000000 --- a/sdks/apigw-manager/.flake8 +++ /dev/null @@ -1,16 +0,0 @@ -[flake8] -ignore = C901,F405,F403,W504,E741,E125,W503,F841,E203,E231,F541,W292 -exclude = - *migrations*, - *.pyc, - .git, - __pycache__, - venv, - *openapi_client*, - manage.py, -max-line-length=119 -max-complexity=12 -format=pylint -show_source = True -statistics = True -count = True \ No newline at end of file diff --git a/sdks/apigw-manager/.isort.cfg b/sdks/apigw-manager/.isort.cfg deleted file mode 100644 index 1db0d245..00000000 --- a/sdks/apigw-manager/.isort.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[settings] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -line_length = 119 -skip = migrations -ensure_newline_before_comments = true \ No newline at end of file diff --git a/sdks/apigw-manager/.pre-commit-config.yaml b/sdks/apigw-manager/.pre-commit-config.yaml deleted file mode 100644 index 0eb49a10..00000000 --- a/sdks/apigw-manager/.pre-commit-config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -fail_fast: true -repos: - - repo: https://github.com/pycqa/isort - rev: 5.4.2 - hooks: - - id: isort - additional_dependencies: [toml] - args: [--settings=.isort.cfg] - - repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - args: [--config=./pyproject.toml] - - repo: https://github.com/pycqa/flake8 - rev: 3.8.3 - hooks: - - id: flake8 - args: [--config=.flake8] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.812" - hooks: - - id: mypy - args: [--config-file=mypy.ini] diff --git a/sdks/apigw-manager/CHANGE.md b/sdks/apigw-manager/CHANGE.md index f6f4e910..d00ea8da 100644 --- a/sdks/apigw-manager/CHANGE.md +++ b/sdks/apigw-manager/CHANGE.md @@ -1,9 +1,18 @@ ## Change logs -### 2.0.2 -- 优化请求 bk-apigateway 接口失败时,打印的错误消息 +### 3.0.0 - 添加指令 add_related_apps,支持为网关添加关联应用 - definition.yaml 添加 spec_version 字段,指定配置文件版本号 +- Django Command 中,通过参数 --gateway-name 指定网关 +- 基础镜像 apigw-manager 中,调整指令名称 + - sync-apigateway 改为 sync-apigateway.sh + - apigw-manager 改为 apigw-manager.sh + - call_command 改为 call_command_or_warning + - call_definition_command 改为 call_definition_command_or_warning + - must_call_definition_command 改为 call_definition_command_or_exit +- 基础镜像 apigw-manager 中,sync-apigateway.sh 中去除指令 apply_apigw_permissions +- 优化请求 bk-apigateway 接口失败时,打印的错误消息 +- 优化 README.md,提供 examples ### 2.0.1 - 修复镜像 sync-apigateway 中,同步任务失败时,脚本退出码为 0 的问题 diff --git a/sdks/apigw-manager/Dockerfile b/sdks/apigw-manager/Dockerfile index 1e769fd1..0aa8d3d0 100644 --- a/sdks/apigw-manager/Dockerfile +++ b/sdks/apigw-manager/Dockerfile @@ -4,14 +4,16 @@ ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 RUN python3 -m venv /opt/venv -ENV PATH="/opt/venv/bin:/apigw-manager/demo/bin:$PATH" +ENV PATH="/opt/venv/bin:/apigw-manager/bin:$PATH" RUN pip3 install --upgrade pip COPY src /apigw-manager/src COPY demo /apigw-manager/demo +COPY bin /apigw-manager/bin COPY manage.py /apigw-manager/manage.py COPY pyproject.toml /apigw-manager/pyproject.toml COPY poetry.lock /apigw-manager/poetry.lock +COPY README.md /apigw-manager/README.md WORKDIR /apigw-manager RUN pip3 install .[demo,kubernetes] @@ -19,7 +21,7 @@ RUN python manage.py migrate WORKDIR /data -CMD ["sync-apigateway"] +CMD ["sync-apigateway.sh"] ONBUILD ARG BK_APIGW_NAME ONBUILD ENV BK_APIGW_NAME "${BK_APIGW_NAME}" diff --git a/sdks/apigw-manager/Makefile b/sdks/apigw-manager/Makefile index 22c73d2d..091f4a58 100644 --- a/sdks/apigw-manager/Makefile +++ b/sdks/apigw-manager/Makefile @@ -20,6 +20,10 @@ poetry.lock: pyproject.toml poetry lock --no-update touch poetry.lock +.PHONY: requirements +requirements: poetry.lock + poetry export -f requirements.txt --without-hashes --extras demo --with dev --output requirements_tox.txt + README.rst: README.md m2r --overwrite README.md diff --git a/sdks/apigw-manager/README.md b/sdks/apigw-manager/README.md index 5beb66f2..814420e7 100644 --- a/sdks/apigw-manager/README.md +++ b/sdks/apigw-manager/README.md @@ -1,6 +1,12 @@ # apigw-manager -蓝鲸 API 网关管理 SDK,提供了基本的注册,同步,发布等功能。 +蓝鲸 API 网关管理 SDK 是一个用于管理 API 网关的工具,它提供了一套完整的工具和功能,可以帮助您更轻松地管理 API 网关,提高系统的安全性和可靠性。 + +1. Django Command:SDK 提供了 Django Command,支持网关注册、同步、发布等功能。您可以根据需要编排指令,以满足您的特定需求,并集成到您的项目自动执行 API 网关同步过程,以便更轻松地管理 API 网关。 + +2. Docker 镜像:对于非 Django 项目,提供了 Docker 基础镜像,封装了 SDK 同步网关的相关功能,以便非 Django 项目轻松管理 API 网关。 + +3. Django 中间件:SDK 还提供了 Django 中间件,用于解析 API 网关请求后端接口时添加的请求头 X-Bkapi-JWT,以方便后端服务校验请求是否来自 API 网关。这个中间件可以确保只有来自蓝鲸 API 网关的请求才能访问您的后端服务,从而提高系统的安全性。 ## 安装 基础安装: @@ -9,7 +15,7 @@ pip install apigw-manager ``` -如果需要使用 apigw-manager 的中间件来解析 JWT,可以安装: +如果需要使用 apigw-manager 提供的 Django 中间件解析来自 API 网关的 X-Bkapi-JWT,可以安装: ```shell pip install "apigw-manager[cryptography]" @@ -17,80 +23,193 @@ pip install "apigw-manager[cryptography]" ## 功能 -- 根据预定义的 YAML 文件进行网关创建,更新,发布及资源同步操作 -- 蓝鲸 APIGateway jwt 解析中间件,校验接口请求来自 APIGateway +- 通过预定义的 YAML 文件,您可以轻松地执行网关创建、更新、发布和资源同步操作,从而简化 API 网关管理过程。 +- 使用 Django 中间件,您可以解析蓝鲸 API 网关的 X-Bkapi-JWT 请求头,确保只有来自 API 网关的请求才能访问您的后端服务,提升系统安全性。 ## 根据 YAML 同步网关配置 -### 更新 django settings 配置 +SDK 同步网关配置到 API 网关,支持多种方案: +- 直接使用 Django Command 同步:此方案适用于 Django 项目;Django 项目,可直接执行 SDK 提供的 Django Command 指令 +- 通过镜像方式同步:此方案适用于非 Django 项目;非 Django 项目,无法直接执行 SDK 提供的 Django Command 指令 -在 django settings.py 中定义网关名称和接口地址模板: -```python -# 待同步网关配置的网关名 -BK_APIGW_NAME = "my-apigateway-name" +### 准备工作 -# 需将 bkapi.example.com 替换为真实的云 API 域名,在 PaaS 3.0 部署的应用,可从环境变量中获取 BK_API_URL_TMPL -BK_API_URL_TMPL = "http://bkapi.example.com/api/{api_name}/" +同步网关配置到 API 网关,需要准备网关配置、资源配置、资源文档、自定义同步脚本等数据,可参考目录: ``` - -在 INSTALLED_APPS 中加入以下配置,SDK 将创建表 `apigw_manager_context` 用于存储一些中间数据: -```python -INSTALLED_APPS += [ - 'apigw_manager.apigw', -] +support-files +├── definition.yaml # 维护网关、环境、资源文档路径、主动授权、发布等配置,但不包含资源配置 +├── resources.yaml # 维护资源配置;资源配置可通过 API 网关管理端直接导出,数据量较大,因此单独管理 +├── bin +│   └── sync-apigateway.sh # 自定义同步脚本,Django 项目也可以自定义 Django Command +├── bk_apigw_docs_demo.tgz # 资源文档归档文件,可选;可通过 API 网关管理端导出;与资源文档目录 apidocs 二选一 +└── apidocs # 资源文档目录,可选;可通过 API 网关管理端导出并解压,或者直接维护 markdown 格式文档文件 + ├── zh # 中文文档目录 + │   └── anything.md + └── en # 英文文档目录 + └── anything.md ``` -### definition.yaml -用于定义网关资源,为了简化使用,使用以下模型进行处理: +#### 1. definition.yaml + +用于定义网关、环境等配置,为了简化使用,使用以下模型进行处理: ``` -+---------------------------------+ +--------------------------------+ -| | | | -| | | +----------------------+ | -| ns1: | | |ns1: | | -| key: {{data.key}} | | | key: value_from_data+--+ | +------------------------------+ -| | Render | | | | | Load | | -| +--------------->+ +----------------------+ +---------------->+ api(key="value_from_data") | -| ns2: | | ns2: | | | -| key: {{settings.THE_KEY}} | | key: value_from_settings | +------------------------------+ -| | | | -| | | | -| Template | | YAML | -+---------------------------------+ +--------------------------------+ + Template(definition.yaml) YAML ++--------------------------+ +----------------------------+ +| | | | +--------------------------------------+ +| ns1: | | ns1: | | | +| key: {{environ.KEY1}} | | key: value_from_environ |------>| api1({"key": "value_from_environ"}) | +| | Render | | | | +| +------->+ | Load | | +| ns2: | | ns2: | | | +| key: {{settings.KEY2}} | | key: value_from_settings |------>| api2({"key": "value_from_settings"}) | +| | | | | | +| | | | +--------------------------------------+ ++--------------------------+ +----------------------------+ ``` -definition.yaml 中可以使用 Django 模块语法引用和渲染变量,内置以下变量: -- `settings`:django 提供的配置对象; -- `environ`:环境变量; -- `data`:命令行自定义变量; +definition.yaml 中可以使用 Django 模版语法引用和渲染变量,内置以下变量: +- `settings`:Django 提供的配置对象 +- `environ`:环境变量 + +推荐在一个文件中统一进行定义,用命名空间区分不同配置间的定义,definition.yaml 样例: + +```yaml +# definition.yaml 配置文件版本号,必填,固定值 1 +spec_version: 1 + +# 定义发布内容,用于命令 `create_version_and_release_apigw` +release: + # 发布版本号; + # 资源配置更新,需更新此版本号才会发布资源版本,此版本号和 sdk 版本号一致,错误设置会影响调用方使用 + version: 1.0.0 + # 版本标题 + title: "" + # 版本描述 + comment: "" + +# 定义网关基本信息,用于命令 `sync_apigw_config` +apigateway: + description: "描述" + # 网关的英文描述,蓝鲸官方网关需提供英文描述,以支持国际化 + description_en: "English description" + # 是否公开;公开,则用户可查看资源文档、申请资源权限;不公开,则网关对用户隐藏 + is_public: true + # 标记网关为官方网关,网关名需以 `bk-` 开头,可选;非官方网关,可去除此配置 + api_type: 1 + # 应用请求网关时,是否允许从请求参数 (querystring, body) 中获取蓝鲸认证信息,默认值为 true; + # 如果为 false,则只能从请求头 X-Bkapi-Authorization 获取蓝鲸认证信息; + # 新接入的网关,可以设置为 false,已接入的网关,待推动所有调用者将认证信息放到请求头后,可设置为 false + allow_auth_from_params: false + # 网关请求后端时,是否删除请求参数 (querystring, body) 中的蓝鲸认证敏感信息,比如 bk_token,为 true 表示允许删除; + # 待请求网关的所有调用者,将认证参数放到请求头 X-Bkapi-Authorization 时,可将此值设置为 false + allow_delete_sensitive_params: false + # 网关维护人员,仅维护人员有管理网关的权限 + maintainers: + - "admin" + +# 定义环境信息,用于命令 `sync_apigw_stage` +stage: + name: "prod" + description: "描述" + # 环境的英文名,蓝鲸官方网关需提供,以支持国际化 + description_en: "English description" + # 环境变量;如未使用,可去除此配置 + # vars: + # key: "value" + # 代理配置 + proxy_http: + timeout: 60 + # 负载均衡类型 + Hosts + upstreams: + loadbalance: "roundrobin" + hosts: + # 网关调用后端服务的默认域名或IP,不包含Path,比如:http://api.example.com + - host: "" + weight: 100 + # Header转换;如未使用,可去除此配置 + # transform_headers: + # # 设置Headers + # set: + # X-Token: "token" + +# 主动授权,网关主动给应用,添加访问网关所有资源的权限; +# 用于命令 `grant_apigw_permissions` +grant_permissions: + - bk_app_code: "{{ settings.BK_APP_CODE }}" + # 授权维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源 + grant_dimension: "gateway" + +# 应用申请指定网关所有资源的权限,待网关管理员审批后,应用才可访问网关资源; +# 用于命令 `apply_apigw_permissions` +apply_permissions: + - gateway_name: "{{ settings.BK_APIGW_NAME }}" + # 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源 + grant_dimension: "gateway" + +# 为网关添加关联应用,关联应用可以通过网关 bk-apigateway 的接口操作网关数据;每个网关最多可有 10 个关联应用; +# 用于命令 `add_related_apps` +related_apps: + - "{{ settings.BK_APP_CODE }}" + +# 定义资源文档路径,用于命令 `sync_resource_docs_by_archive`; +# 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档,创建归档文件可使用指令 `tar czvf xxx.tgz en zh`: +# ./ +# - en +# - get_user.md +# - zh +# - get_user.md +resource_docs: + # 资源文档的归档文件,可为 tar.gz,zip 格式文件 + archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}" + # 资源文档目录,basedir 与 archivefile 二者至少一个有效,若同时存在,则 archivefile 优先 + basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}" +``` -推荐在一个文件中统一进行定义,用命名空间来区分不同资源间的定义,[definition.yaml 样例](definition.yaml): -- `apigateway`:定义网关基本信息,用于命令 `sync_apigw_config`; -- `stage`:定义环境信息,用于命令 `sync_apigw_stage`; -- `apply_permissions`:申请网关权限,用于命令 `apply_apigw_permissions`; -- `grant_permissions`:应用主动授权,用于命令 `grant_apigw_permissions`; -- `release`:定义发布内容,用于命令 `create_version_and_release_apigw`; -- `resource_docs`:定义资源文档,用于命令 `sync_resource_docs_by_archive`; +**注意:** +- 同步资源后,需要创建版本并发布才能生效,发布数据定义于 definition.yaml `release` +- 资源配置 resources.yaml 变更时,需要更新 definition.yaml `release` 中的版本号 version,以便正确创建资源版本及 SDK -**注意,同步资源后需要发布后才生效,发布内容定义于 `release`,请及时更新对应的版本信息,否则可能会导致资源漏发或 SDK 版本异常的情况** +#### 2. resources.yaml -特别的,为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。 +用于定义资源配置,建议通过网关管理端导出。为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。 -### 同步命令 -约定:definition.yaml 用于维护网关基本定义,不包含资源定义,资源定义使用 resources.yaml 单独定义,基本的网关同步命令顺序如下,可参考使用: -```shell -python manage.py sync_apigw_config -f definition.yaml # 同步网关基本信息 -python manage.py sync_apigw_stage -f definition.yaml # 同步网关环境信息 -python manage.py apply_apigw_permissions -f definition.yaml # 申请网关权限,如无可跳过 -python manage.py grant_apigw_permissions -f definition.yaml # 为应用主动授权,如无可跳过 -python manage.py sync_apigw_resources -f resources.yaml # 同步网关资源 -python manage.py sync_resource_docs_by_archive -f definition.yaml # 同步资源文档 -python manage.py create_version_and_release_apigw -f definition.yaml --generate-sdks # 创建资源版本并发布,同时生成 SDK -python manage.py fetch_apigw_public_key # 获取网关公钥 -python manage.py fetch_esb_public_key # 获取 ESB 公钥(专用于同时接入 ESB 和网关的系统) +#### 3. apidocs(可选) + +资源文档,资源文档为 markdown 格式。资源文档的文件名,应为 `资源名称` + `.md` 格式,假如资源名称为 get_user,则文档文件名应为 get_user.md。 +将资源的中文文档放到目录 `zh` 下,英文文档放到目录 `en` 下,如果某语言文档不存在,可忽略对应目录。 + +文档文件目录样例如下: ``` +. +├── en +│ ├── create_user.md +│ └── get_user.md +└── zh + ├── create_user.md + └── get_user.md +``` + +导入资源文档时,可以直接使用资源文档归档文件,也可以使用资源文档目录。参考上文 definition.yaml 样例, +在项目 definition.yaml 文件中,修改资源文档相关配置 resource_docs: +```yaml +resource_docs: + # 资源文档的归档文件,可为 tar.gz,zip 格式文件;创建归档文件可使用指令 `tar czvf xxx.tgz en zh` + # archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}" + # 资源文档目录,basedir 与 archivefile 二者至少一个有效,若同时存在,则 archivefile 优先 + # basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}" + basedir: "support-files/apidocs/" +``` + +### 方案一:直接使用 Django Command 同步 -## 校验请求来自 APIGateway +此方案适用于 Django 项目,具体请参考 [sync-apigateway-with-django.md](docs/sync-apigateway-with-django.md) + +### 方案二:通过镜像方式同步 + +此方案适用于非 Django 项目,具体请参考 [sync-apigateway-with-docker.md](docs/sync-apigateway-with-docker.md) + +## 校验请求来自 API 网关 如果应用需要认证 API 网关传递过来的 JWT 信息,在 MIDDLEWARE 中加入: @@ -114,7 +233,7 @@ AUTHENTICATION_BACKENDS += [ ] ``` -### 中间件 +### Django 中间件 #### ApiGatewayJWTGenericMiddleware 认证 JWT 信息,在 `request` 中注入 `jwt` 对象,有以下属性: @@ -139,7 +258,7 @@ auth.authenticate(request, username=username, verified=verified) - 已认证的用户名,通过 `UserModel` 根据 `username` 获取用户,不存在时返回 `None`; - 未认证的用户名,返回 `AnonymousUser`,可通过继承后修改 `make_anonymous_user` 的实现来定制具体字段; -## 本地开发测试 +### 本地开发测试 如果使用了 `ApiGatewayJWTGenericMiddleware` 中间件,在本地开发测试时在请求中带上合法的 JWT 是相对来说较困难的,这个时候我们可以通过使用测试用的 `JWTProvider` 来解决这个问题 @@ -159,57 +278,11 @@ APIGW_MANAGER_DUMMY_PAYLOAD_APP_CODE # JWT payload 中的 app_code APIGW_MANAGER_DUMMY_PAYLOAD_USERNAME # JWT payload 中的 username ``` +## FAQ -## 镜像 -### 基础镜像 -基础镜像通过 [Dockerfile](Dockerfile) 进行构建,该镜像封装了 [demo](demo) 项目,可读取 /data/ 目录,直接进行网关注册和同步操作,目录约定: -- */data/definition.yaml*:网关定义文件,用于注册网关; -- */data/resources.yaml*:资源定义文件,用于同步网关资源,可通过网关导出; -- */data/docs*:文档目录,可通过网关导出后解压; - -镜像执行同步时,需要额外的环境变量支持: -- `BK_APIGW_NAME`:网关名称; -- `BK_API_URL_TMPL`:云网关 API 地址模板; -- `BK_APP_CODE`:应用名称; -- `BK_APP_SECRET`:应用密钥; -- `DATABASE_URL`:数据库连接地址,格式:`mysql://username:password@host:port/dbname`; -- `APIGW_PUBLIC_KEY_PATH`:网关公钥保存路径,默认为当前目录下 `apigateway.pub`; - -#### 如何获得网关公钥 -1. 如果设置了环境变量 `APIGW_PUBLIC_KEY_PATH`,同步后可读取该文件获取; -2. 如果通过 `DATABASE_URL` 设置了外部数据库,可通过执行以下 SQL 查询: +#### Docker 镜像方案如何获得网关公钥 +1. 可设置环境变量 `APIGW_PUBLIC_KEY_PATH`(默认值:apigateway.pub),同步后可读取该文件获取; +2. 可设置环境变量 `DATABASE_URL`,指定外部数据库,同步后可通过执行以下 SQL 查询: ```sql select value from apigw_manager_context where scope="public_key" and key=""; - ``` - -### 通过外部挂载方式同步 -通过外部文件挂载的方式,将对应的目录挂载到 `/data/` 目录下,可通过以下类似的命令进行同步: -```shell -docker run --rm \ - -v //:/data/ \ - -e BK_APIGW_NAME= \ - -e BK_API_URL_TMPL= \ - -e BK_APP_CODE= \ - -e BK_APP_SECRET= \ - -e DATABASE_URL= \ - apigw-manager -``` - -同步后,会在 ** 目录下获得网关公钥文件 *apigateway.pub*。 - -### 通过镜像方式同步 -可将 apigw-manager 作为基础镜像,将配置文件和文档一并构建成一个新镜像,然后通过如 K8S Job 方式进行同步,构建 Dockerfile 参考: -```Dockerfile -FROM apigw-manager - -COPY /data/ -``` - -环境变量可通过运行时传入,也可以通过构建参数提前设置(仅支持 `BK_APIGW_NAME` 和 `BK_APP_CODE`): -```shell -docker build \ - -t my-apigw-manager \ - --build-arg BK_APIGW_NAME= \ - --build-arg BK_APP_CODE= \ - -f Dockerfile . -``` + ``` \ No newline at end of file diff --git a/sdks/apigw-manager/README.rst b/sdks/apigw-manager/README.rst index c95b8ff3..1341266c 100644 --- a/sdks/apigw-manager/README.rst +++ b/sdks/apigw-manager/README.rst @@ -1,11 +1,18 @@ -.. role:: raw-html-m2r(raw) - :format: html - apigw-manager ============= -蓝鲸 API 网关管理 SDK,提供了基本的注册,同步,发布等功能。 +蓝鲸 API 网关管理 SDK 是一个用于管理 API 网关的工具,它提供了一套完整的工具和功能,可以帮助您更轻松地管理 API 网关,提高系统的安全性和可靠性。 + + +#. + Django Command:SDK 提供了 Django Command,支持网关注册、同步、发布等功能。您可以根据需要编排指令,以满足您的特定需求,并集成到您的项目自动执行 API 网关同步过程,以便更轻松地管理 API 网关。 + +#. + Docker 镜像:对于非 Django 项目,提供了 Docker 基础镜像,封装了 SDK 同步网关的相关功能,以便非 Django 项目轻松管理 API 网关。 + +#. + Django 中间件:SDK 还提供了 Django 中间件,用于解析 API 网关请求后端接口时添加的请求头 X-Bkapi-JWT,以方便后端服务校验请求是否来自 API 网关。这个中间件可以确保只有来自蓝鲸 API 网关的请求才能访问您的后端服务,从而提高系统的安全性。 安装 ---- @@ -16,7 +23,7 @@ apigw-manager pip install apigw-manager -如果需要使用 apigw-manager 的中间件来解析 JWT,可以安装: +如果需要使用 apigw-manager 提供的 Django 中间件解析来自 API 网关的 X-Bkapi-JWT,可以安装: .. code-block:: shell @@ -26,94 +33,210 @@ apigw-manager ---- -* 根据预定义的 YAML 文件进行网关创建,更新,发布及资源同步操作 -* 蓝鲸 APIGateway jwt 解析中间件,校验接口请求来自 APIGateway +* 通过预定义的 YAML 文件,您可以轻松地执行网关创建、更新、发布和资源同步操作,从而简化 API 网关管理过程。 +* 使用 Django 中间件,您可以解析蓝鲸 API 网关的 X-Bkapi-JWT 请求头,确保只有来自 API 网关的请求才能访问您的后端服务,提升系统安全性。 根据 YAML 同步网关配置 ---------------------- -更新 django settings 配置 -^^^^^^^^^^^^^^^^^^^^^^^^^ +SDK 同步网关配置到 API 网关,支持多种方案: -在 django settings.py 中定义网关名称和接口地址模板: -.. code-block:: python +* 直接使用 Django Command 同步:此方案适用于 Django 项目;Django 项目,可直接执行 SDK 提供的 Django Command 指令 +* 通过镜像方式同步:此方案适用于非 Django 项目;非 Django 项目,无法直接执行 SDK 提供的 Django Command 指令 - # 待同步网关配置的网关名 - BK_APIGW_NAME = "my-apigateway-name" - - # 需将 bkapi.example.com 替换为真实的云 API 域名,在 PaaS 3.0 部署的应用,可从环境变量中获取 BK_API_URL_TMPL - BK_API_URL_TMPL = "http://bkapi.example.com/api/{api_name}/" +准备工作 +^^^^^^^^ -在 INSTALLED_APPS 中加入以下配置,SDK 将创建表 ``apigw_manager_context`` 用于存储一些中间数据: +同步网关配置到 API 网关,需要准备网关配置、资源配置、资源文档、自定义同步脚本等数据,可参考目录: -.. code-block:: python +.. code-block:: - INSTALLED_APPS += [ - 'apigw_manager.apigw', - ] + support-files + ├── definition.yaml # 维护网关、环境、资源文档路径、主动授权、发布等配置,但不包含资源配置 + ├── resources.yaml # 维护资源配置;资源配置可通过 API 网关管理端直接导出,数据量较大,因此单独管理 + ├── bin + │   └── sync-apigateway.sh # 自定义同步脚本,Django 项目也可以自定义 Django Command + ├── bk_apigw_docs_demo.tgz # 资源文档归档文件,可选;可通过 API 网关管理端导出;与资源文档目录 apidocs 二选一 + └── apidocs # 资源文档目录,可选;可通过 API 网关管理端导出并解压,或者直接维护 markdown 格式文档文件 + ├── zh # 中文文档目录 + │   └── anything.md + └── en # 英文文档目录 + └── anything.md -definition.yaml -^^^^^^^^^^^^^^^ +1. definition.yaml +~~~~~~~~~~~~~~~~~~ -用于定义网关资源,为了简化使用,使用以下模型进行处理: +用于定义网关、环境等配置,为了简化使用,使用以下模型进行处理: .. code-block:: - +---------------------------------+ +--------------------------------+ - | | | | - | | | +----------------------+ | - | ns1: | | |ns1: | | - | key: {{data.key}} | | | key: value_from_data+--+ | +------------------------------+ - | | Render | | | | | Load | | - | +--------------->+ +----------------------+ +---------------->+ api(key="value_from_data") | - | ns2: | | ns2: | | | - | key: {{settings.THE_KEY}} | | key: value_from_settings | +------------------------------+ - | | | | - | | | | - | Template | | YAML | - +---------------------------------+ +--------------------------------+ + Template(definition.yaml) YAML + +--------------------------+ +----------------------------+ + | | | | +--------------------------------------+ + | ns1: | | ns1: | | | + | key: {{environ.KEY1}} | | key: value_from_environ |------>| api1({"key": "value_from_environ"}) | + | | Render | | | | + | +------->+ | Load | | + | ns2: | | ns2: | | | + | key: {{settings.KEY2}} | | key: value_from_settings |------>| api2({"key": "value_from_settings"}) | + | | | | | | + | | | | +--------------------------------------+ + +--------------------------+ +----------------------------+ + +definition.yaml 中可以使用 Django 模版语法引用和渲染变量,内置以下变量: + + +* ``settings``\ :Django 提供的配置对象 +* ``environ``\ :环境变量 + +推荐在一个文件中统一进行定义,用命名空间区分不同配置间的定义,definition.yaml 样例: + +.. code-block:: yaml + + # definition.yaml 配置文件版本号,必填,固定值 1 + spec_version: 1 + + # 定义发布内容,用于命令 `create_version_and_release_apigw` + release: + # 发布版本号; + # 资源配置更新,需更新此版本号才会发布资源版本,此版本号和 sdk 版本号一致,错误设置会影响调用方使用 + version: 1.0.0 + # 版本标题 + title: "" + # 版本描述 + comment: "" + + # 定义网关基本信息,用于命令 `sync_apigw_config` + apigateway: + description: "描述" + # 网关的英文描述,蓝鲸官方网关需提供英文描述,以支持国际化 + description_en: "English description" + # 是否公开;公开,则用户可查看资源文档、申请资源权限;不公开,则网关对用户隐藏 + is_public: true + # 标记网关为官方网关,网关名需以 `bk-` 开头,可选;非官方网关,可去除此配置 + api_type: 1 + # 应用请求网关时,是否允许从请求参数 (querystring, body) 中获取蓝鲸认证信息,默认值为 true; + # 如果为 false,则只能从请求头 X-Bkapi-Authorization 获取蓝鲸认证信息; + # 新接入的网关,可以设置为 false,已接入的网关,待推动所有调用者将认证信息放到请求头后,可设置为 false + allow_auth_from_params: false + # 网关请求后端时,是否删除请求参数 (querystring, body) 中的蓝鲸认证敏感信息,比如 bk_token,为 true 表示允许删除; + # 待请求网关的所有调用者,将认证参数放到请求头 X-Bkapi-Authorization 时,可将此值设置为 false + allow_delete_sensitive_params: false + # 网关维护人员,仅维护人员有管理网关的权限 + maintainers: + - "admin" + + # 定义环境信息,用于命令 `sync_apigw_stage` + stage: + name: "prod" + description: "描述" + # 环境的英文名,蓝鲸官方网关需提供,以支持国际化 + description_en: "English description" + # 环境变量;如未使用,可去除此配置 + # vars: + # key: "value" + # 代理配置 + proxy_http: + timeout: 60 + # 负载均衡类型 + Hosts + upstreams: + loadbalance: "roundrobin" + hosts: + # 网关调用后端服务的默认域名或IP,不包含Path,比如:http://api.example.com + - host: "" + weight: 100 + # Header转换;如未使用,可去除此配置 + # transform_headers: + # # 设置Headers + # set: + # X-Token: "token" + + # 主动授权,网关主动给应用,添加访问网关所有资源的权限; + # 用于命令 `grant_apigw_permissions` + grant_permissions: + - bk_app_code: "{{ settings.BK_APP_CODE }}" + # 授权维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源 + grant_dimension: "gateway" + + # 应用申请指定网关所有资源的权限,待网关管理员审批后,应用才可访问网关资源; + # 用于命令 `apply_apigw_permissions` + apply_permissions: + - gateway_name: "{{ settings.BK_APIGW_NAME }}" + # 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源 + grant_dimension: "gateway" + + # 为网关添加关联应用,关联应用可以通过网关 bk-apigateway 的接口操作网关数据;每个网关最多可有 10 个关联应用; + # 用于命令 `add_related_apps` + related_apps: + - "{{ settings.BK_APP_CODE }}" + + # 定义资源文档路径,用于命令 `sync_resource_docs_by_archive`; + # 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档,创建归档文件可使用指令 `tar czvf xxx.tgz en zh`: + # ./ + # - en + # - get_user.md + # - zh + # - get_user.md + resource_docs: + # 资源文档的归档文件,可为 tar.gz,zip 格式文件 + archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}" + # 资源文档目录,basedir 与 archivefile 二者至少一个有效,若同时存在,则 archivefile 优先 + basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}" + +**注意:** + + +* 同步资源后,需要创建版本并发布才能生效,发布数据定义于 definition.yaml ``release`` +* 资源配置 resources.yaml 变更时,需要更新 definition.yaml ``release`` 中的版本号 version,以便正确创建资源版本及 SDK + +2. resources.yaml +~~~~~~~~~~~~~~~~~ + +用于定义资源配置,建议通过网关管理端导出。为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。 + +3. apidocs(可选) +~~~~~~~~~~~~~~~~~~ + +资源文档,资源文档为 markdown 格式。资源文档的文件名,应为 ``资源名称`` + ``.md`` 格式,假如资源名称为 get_user,则文档文件名应为 get_user.md。 +将资源的中文文档放到目录 ``zh`` 下,英文文档放到目录 ``en`` 下,如果某语言文档不存在,可忽略对应目录。 + +文档文件目录样例如下: -definition.yaml 中可以使用 Django 模块语法引用和渲染变量,内置以下变量: - - -* ``settings``\ :django 提供的配置对象; -* ``environ``\ :环境变量; -* ``data``\ :命令行自定义变量; - -推荐在一个文件中统一进行定义,用命名空间来区分不同资源间的定义,\ `definition.yaml 样例 `_\ : +.. code-block:: + . + ├── en + │ ├── create_user.md + │ └── get_user.md + └── zh + ├── create_user.md + └── get_user.md -* ``apigateway``\ :定义网关基本信息,用于命令 ``sync_apigw_config``\ ; -* ``stage``\ :定义环境信息,用于命令 ``sync_apigw_stage``\ ; -* ``apply_permissions``\ :申请网关权限,用于命令 ``apply_apigw_permissions``\ ; -* ``grant_permissions``\ :应用主动授权,用于命令 ``grant_apigw_permissions``\ ; -* ``release``\ :定义发布内容,用于命令 ``create_version_and_release_apigw``\ ; -* ``resource_docs``\ :定义资源文档,用于命令 ``sync_resource_docs_by_archive``\ ; +导入资源文档时,可以直接使用资源文档归档文件,也可以使用资源文档目录。参考上文 definition.yaml 样例, +在项目 definition.yaml 文件中,修改资源文档相关配置 resource_docs: -**注意,同步资源后需要发布后才生效,发布内容定义于 ``release``\ ,请及时更新对应的版本信息,否则可能会导致资源漏发或 SDK 版本异常的情况** +.. code-block:: yaml -特别的,为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。 + resource_docs: + # 资源文档的归档文件,可为 tar.gz,zip 格式文件;创建归档文件可使用指令 `tar czvf xxx.tgz en zh` + # archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}" + # 资源文档目录,basedir 与 archivefile 二者至少一个有效,若同时存在,则 archivefile 优先 + # basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}" + basedir: "support-files/apidocs/" -同步命令 -^^^^^^^^ +方案一:直接使用 Django Command 同步 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -约定:definition.yaml 用于维护网关基本定义,不包含资源定义,资源定义使用 resources.yaml 单独定义,基本的网关同步命令顺序如下,可参考使用: +此方案适用于 Django 项目,具体请参考 `sync-apigateway-with-django.md `_ -.. code-block:: shell +方案二:通过镜像方式同步 +^^^^^^^^^^^^^^^^^^^^^^^^ - python manage.py sync_apigw_config -f definition.yaml # 同步网关基本信息 - python manage.py sync_apigw_stage -f definition.yaml # 同步网关环境信息 - python manage.py apply_apigw_permissions -f definition.yaml # 申请网关权限,如无可跳过 - python manage.py grant_apigw_permissions -f definition.yaml # 为应用主动授权,如无可跳过 - python manage.py sync_apigw_resources -f resources.yaml # 同步网关资源 - python manage.py sync_resource_docs_by_archive -f definition.yaml # 同步资源文档 - python manage.py create_version_and_release_apigw -f definition.yaml --generate-sdks # 创建资源版本并发布,同时生成 SDK - python manage.py fetch_apigw_public_key # 获取网关公钥 - python manage.py fetch_esb_public_key # 获取 ESB 公钥(专用于同时接入 ESB 和网关的系统) +此方案适用于非 Django 项目,具体请参考 `sync-apigateway-with-docker.md `_ -校验请求来自 APIGateway ------------------------ +校验请求来自 API 网关 +--------------------- 如果应用需要认证 API 网关传递过来的 JWT 信息,在 MIDDLEWARE 中加入: @@ -141,8 +264,8 @@ apigw_manager 默认提供了一个基于 User Model 实现的 authentication ba 'apigw_manager.apigw.authentication.UserModelBackend', ] -中间件 -^^^^^^ +Django 中间件 +^^^^^^^^^^^^^ ApiGatewayJWTGenericMiddleware ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -184,7 +307,7 @@ UserModelBackend * 未认证的用户名,返回 ``AnonymousUser``\ ,可通过继承后修改 ``make_anonymous_user`` 的实现来定制具体字段; 本地开发测试 ------------- +^^^^^^^^^^^^ 如果使用了 ``ApiGatewayJWTGenericMiddleware`` 中间件,在本地开发测试时在请求中带上合法的 JWT 是相对来说较困难的,这个时候我们可以通过使用测试用的 ``JWTProvider`` 来解决这个问题 @@ -204,74 +327,15 @@ UserModelBackend APIGW_MANAGER_DUMMY_PAYLOAD_APP_CODE # JWT payload 中的 app_code APIGW_MANAGER_DUMMY_PAYLOAD_USERNAME # JWT payload 中的 username -镜像 ----- - -基础镜像 -^^^^^^^^ - -基础镜像通过 `Dockerfile `_ 进行构建,该镜像封装了 `demo `_ 项目,可读取 /data/ 目录,直接进行网关注册和同步操作,目录约定: +FAQ +--- +Docker 镜像方案如何获得网关公钥 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* */data/definition.yaml*\ :网关定义文件,用于注册网关; -* */data/resources.yaml*\ :资源定义文件,用于同步网关资源,可通过网关导出; -* */data/docs*\ :文档目录,可通过网关导出后解压; -镜像执行同步时,需要额外的环境变量支持: - - -* ``BK_APIGW_NAME``\ :网关名称; -* ``BK_API_URL_TMPL``\ :云网关 API 地址模板; -* ``BK_APP_CODE``\ :应用名称; -* ``BK_APP_SECRET``\ :应用密钥; -* ``DATABASE_URL``\ :数据库连接地址,格式:\ ``mysql://username:password@host:port/dbname``\ ; -* ``APIGW_PUBLIC_KEY_PATH``\ :网关公钥保存路径,默认为当前目录下 ``apigateway.pub``\ ; - -如何获得网关公钥 -~~~~~~~~~~~~~~~~ - - -#. 如果设置了环境变量 ``APIGW_PUBLIC_KEY_PATH``\ ,同步后可读取该文件获取; -#. 如果通过 ``DATABASE_URL`` 设置了外部数据库,可通过执行以下 SQL 查询: +#. 可设置环境变量 ``APIGW_PUBLIC_KEY_PATH``\ (默认值:apigateway.pub),同步后可读取该文件获取; +#. 可设置环境变量 ``DATABASE_URL``\ ,指定外部数据库,同步后可通过执行以下 SQL 查询: .. code-block:: sql select value from apigw_manager_context where scope="public_key" and key=""; - -通过外部挂载方式同步 -^^^^^^^^^^^^^^^^^^^^ - -通过外部文件挂载的方式,将对应的目录挂载到 ``/data/`` 目录下,可通过以下类似的命令进行同步: - -.. code-block:: shell - - docker run --rm \ - -v //:/data/ \ - -e BK_APIGW_NAME= \ - -e BK_API_URL_TMPL= \ - -e BK_APP_CODE= \ - -e BK_APP_SECRET= \ - -e DATABASE_URL= \ - apigw-manager - -同步后,会在 *\ :raw-html-m2r:``\ * 目录下获得网关公钥文件 *apigateway.pub*\ 。 - -通过镜像方式同步 -^^^^^^^^^^^^^^^^ - -可将 apigw-manager 作为基础镜像,将配置文件和文档一并构建成一个新镜像,然后通过如 K8S Job 方式进行同步,构建 Dockerfile 参考: - -.. code-block:: Dockerfile - - FROM apigw-manager - - COPY /data/ - -环境变量可通过运行时传入,也可以通过构建参数提前设置(仅支持 ``BK_APIGW_NAME`` 和 ``BK_APP_CODE``\ ): - -.. code-block:: shell - - docker build \ - -t my-apigw-manager \ - --build-arg BK_APIGW_NAME= \ - --build-arg BK_APP_CODE= \ - -f Dockerfile . diff --git a/sdks/apigw-manager/demo/bin/apigw-manager b/sdks/apigw-manager/bin/apigw-manager.sh similarity index 52% rename from sdks/apigw-manager/demo/bin/apigw-manager rename to sdks/apigw-manager/bin/apigw-manager.sh index ca8f8ad7..6b89da52 100755 --- a/sdks/apigw-manager/demo/bin/apigw-manager +++ b/sdks/apigw-manager/bin/apigw-manager.sh @@ -1,7 +1,6 @@ #!/bin/bash bin_dir=$(dirname "$0") -demo_dir=$(dirname "${bin_dir}") -root_dir=$(dirname "${demo_dir}") +root_dir=$(dirname "${bin_dir}") python "${root_dir}/manage.py" "$@" \ No newline at end of file diff --git a/sdks/apigw-manager/bin/functions.sh b/sdks/apigw-manager/bin/functions.sh new file mode 100755 index 00000000..82e283d0 --- /dev/null +++ b/sdks/apigw-manager/bin/functions.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# 本文定义与业务逻辑无关的通用函数 + +log() { + NOW=$(date +"%Y-%m-%d %H:%M:%S") + echo "${NOW} [$1] $2" +} + +log_info() { + log "INFO" "$1" +} + +log_warn() { + log "WARN" "$1" +} + +log_error() { + log "ERROR" "$1" +} + +title() { + echo "====== $1 ======" +} + +call_command_or_warning() { + command=$1 + shift + + log_info "Running command ${command}" + + apigw-manager.sh "${command}" "$@" + status=$? + + if [ ${status} -ne 0 ]; then + log_warn "Command ${command} failed with status ${status}" + return ${status} + fi + + return 0 +} + +call_command_or_exit() { + command=$1 + shift + + call_command_or_warning "${command}" "$@" + status=$? + + if [ ${status} -ne 0 ]; then + log_error "Crash and exit during command ${command}" + exit ${status} + fi + + return 0 +} + +call_definition_command_or_warning() { + command=$1 + definition=$2 + shift 2 + + # check definition exists + if [ ! -f "${definition}" ]; then + log_warn "Definition file ${definition} does not exist, skipped" + return 0 + fi + + call_command_or_warning "${command}" -f "${definition}" "$@" + status=$? + + if [ ${status} -ne 0 ]; then + log_warn "Command ${command} failed with status ${status}" + return ${status} + fi + + return 0 +} + +call_definition_command_or_exit() { + command=$1 + definition=$2 + shift 2 + + call_definition_command_or_warning "${command}" "${definition}" "$@" + status=$? + + if [ ${status} -ne 0 ]; then + log_error "Crash and exit during command ${command}" + exit ${status} + fi + + return 0 +} diff --git a/sdks/apigw-manager/bin/sync-apigateway.sh b/sdks/apigw-manager/bin/sync-apigateway.sh new file mode 100755 index 00000000..8b57770f --- /dev/null +++ b/sdks/apigw-manager/bin/sync-apigateway.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +source $(dirname "$0")/functions.sh + +definition_file="${definition_file:-definition.yaml}" +resources_file="${resources_file:-resources.yaml}" + +title "begin to db migrate" +call_command_or_warning migrate apigw + +title "syncing apigateway" +call_definition_command_or_exit sync_apigw_config "${definition_file}" ${SYNC_APIGW_CONFIG_ARGS} +call_definition_command_or_exit sync_apigw_stage "${definition_file}" ${SYNC_APIGW_STAGE_ARGS} +call_definition_command_or_exit grant_apigw_permissions "${definition_file}" ${GRANT_APIGW_PERMISSIONS_ARGS} +call_definition_command_or_exit sync_apigw_resources "${resources_file}" ${SYNC_APIGW_RESOURCES_ARGS:-"--delete"} +call_definition_command_or_exit sync_resource_docs_by_archive "${definition_file}" ${SYNC_RESOURCE_DOCS_BY_ARCHIVE_ARGS:-"--safe-mode"} + +title "fetch apigateway public key" +apigw-manager.sh fetch_apigw_public_key --print > "${APIGW_PUBLIC_KEY_PATH:-apigateway.pub}" + +title "fetch esb public key" +call_command_or_warning fetch_esb_public_key ${FETCH_ESB_PUBLIC_KEY_ARGS} + +title "releasing" +call_definition_command_or_exit create_version_and_release_apigw "${definition_file}" ${CREATE_VERSION_AND_RELEASE_APIGW_ARGS:-"--generate-sdks"} + +log_info "done" diff --git a/sdks/apigw-manager/definition.yaml b/sdks/apigw-manager/definition.yaml deleted file mode 100644 index d8dab221..00000000 --- a/sdks/apigw-manager/definition.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# definition.yaml 配置文件版本号,必填,固定值 1 -spec_version: 1 - -release: - # 发布版本号, - # 资源配置更新,需更新此版本号才会发布资源版本,此版本号和 sdk 版本号一致,错误设置会影响调用方使用 - version: 1.0.0 - # 版本标题 - title: "" - # 版本描述 - comment: "" - -apigateway: - description: "描述" - description_en: "英文描述" - is_public: true - # 标记网关为官方网关,网关名需以 `bk-` 开头,可选 - api_type: 1 - maintainers: - - "admin" - -stage: - name: "prod" - description: "描述" - description_en: "英文描述" - # 环境变量 - vars: - key: "value" - # 代理配置 - proxy_http: - timeout: 60 - # 负载均衡类型 + Hosts - upstreams: - loadbalance: "roundrobin" - hosts: - - host: "http://127.0.0.1" - weight: 100 - # Header转换 - transform_headers: - # 设置Headers - set: - X-Token: "token" - # 流量控制 - rate_limit: - enabled: false - rate: - tokens: 5000 - period: 60 - -# 主动授权,网关主动给应用,添加访问网关所有资源的权限 -grant_permissions: - - bk_app_code: "{{ settings.BK_APP_CODE }}" - # 按网关授权,包括网关下所有资源,包括未来新创建的资源 - grant_dimension: "gateway" - -# 应用申请指定网关所有资源的权限,待网关管理员审批后,应用才可访问网关资源 -apply_permissions: - - api_name: "{{ settings.BK_APIGW_NAME }}" - -# 为网关添加关联应用,关联应用可以通过网关 bk-apigateway 的接口操作网关数据;每个网关最多可有 10 个关联应用 -related_apps: - - "{{ settings.BK_APP_CODE }}" - -# 网关资源,建议资源配置采用单独的配置文件,可通过网关管理端导出资源配置 -resources: - swagger: "2.0" - paths: [] - -# 资源文档 -# 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档,创建归档文件可使用指令 `tar czvf xxx.tgz en zh`: -# ./ -# - en -# - get_user.md -# - zh -# - get_user.md -resource_docs: - # 资源文档的归档文件,可为 tar.gz,zip 格式文件 - archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}" - # 资源文档目录,basedir 与 archivefile 二者至少一个有效,若同时存在,则 archivefile 优先 - basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}" diff --git a/sdks/apigw-manager/demo/bin/sync-apigateway b/sdks/apigw-manager/demo/bin/sync-apigateway deleted file mode 100755 index 2e758c8e..00000000 --- a/sdks/apigw-manager/demo/bin/sync-apigateway +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash - -log() { - NOW=$(date +"%Y-%m-%d %H:%M:%S") - echo "${NOW} [$1] $2" -} - -log_info() { - log "INFO" "$1" -} - -log_warn() { - log "WARN" "$1" -} - -log_error() { - log "ERROR" "$1" -} - -title() { - echo "====== $1 ======" -} - -call_command() { - command=$1 - shift - - log_info "Running command ${command}" - - apigw-manager "${command}" "$@" - status=$? - - if [ ${status} -ne 0 ]; then - log_warn "Command ${command} failed with status ${status}" - return ${status} - fi - - return 0 -} - -call_definition_command() { - command=$1 - definition=$2 - shift 2 - - # check definition exists - if [ ! -f "${definition}" ]; then - log_warn "Definition file ${definition} does not exist, skipped" - return 0 - fi - - call_command "${command}" -f "${definition}" "$@" - status=$? - - if [ ${status} -ne 0 ]; then - log_warn "Command ${command} failed with status ${status}" - return ${status} - fi - - return 0 -} - -must_call_definition_command() { - command=$1 - definition=$2 - shift 2 - - call_definition_command "${command}" "${definition}" "$@" - status=$? - - if [ ${status} -ne 0 ]; then - log_error "Crash during command ${command}" - exit ${status} - fi - - return 0 -} - -definition_file="${definition_file:-definition.yaml}" -resources_file="${resources_file:-resources.yaml}" - -title "begin to db migrate" -call_command migrate apigw - -title "syncing apigateway" -must_call_definition_command sync_apigw_config "${definition_file}" ${SYNC_APIGW_CONFIG_ARGS} -must_call_definition_command sync_apigw_stage "${definition_file}" ${SYNC_APIGW_STAGE_ARGS} -must_call_definition_command apply_apigw_permissions "${definition_file}" ${APPLY_APIGW_PERMISSIONS_ARGS} -must_call_definition_command grant_apigw_permissions "${definition_file}" ${GRANT_APIGW_PERMISSIONS_ARGS} -must_call_definition_command sync_apigw_resources "${resources_file}" ${SYNC_APIGW_RESOURCES_ARGS:-"--delete"} -must_call_definition_command sync_resource_docs_by_archive "${definition_file}" ${SYNC_RESOURCE_DOCS_BY_ARCHIVE_ARGS:-"--safe-mode"} - -title "fetch apigateway public key" -apigw-manager fetch_apigw_public_key --print > "${APIGW_PUBLIC_KEY_PATH:-apigateway.pub}" - -title "fetch esb public key" -call_command fetch_esb_public_key ${FETCH_ESB_PUBLIC_KEY_ARGS} - -title "releasing" -must_call_definition_command create_version_and_release_apigw "${definition_file}" ${CREATE_VERSION_AND_RELEASE_APIGW_ARGS:-"--generate-sdks"} - -title "done" diff --git a/sdks/apigw-manager/demo/settings.py b/sdks/apigw-manager/demo/settings.py index b5def70a..50d051b3 100644 --- a/sdks/apigw-manager/demo/settings.py +++ b/sdks/apigw-manager/demo/settings.py @@ -18,7 +18,7 @@ try: import pymysql - pymysql.version_info = (1, 4, 6, 'final', 0) # change mysqlclient version + pymysql.version_info = (1, 4, 6, "final", 0) # change mysqlclient version pymysql.install_as_MySQLdb() except ImportError: pass @@ -61,14 +61,14 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - 'apigw_manager.apigw.authentication.ApiGatewayJWTGenericMiddleware', - 'apigw_manager.apigw.authentication.ApiGatewayJWTAppMiddleware', - 'apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware', + "apigw_manager.apigw.authentication.ApiGatewayJWTGenericMiddleware", + "apigw_manager.apigw.authentication.ApiGatewayJWTAppMiddleware", + "apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware", ] AUTHENTICATION_BACKENDS = [ - 'django.contrib.auth.backends.ModelBackend', - 'apigw_manager.apigw.authentication.UserModelBackend', + "django.contrib.auth.backends.ModelBackend", + "apigw_manager.apigw.authentication.UserModelBackend", ] ROOT_URLCONF = "demo.urls" @@ -142,7 +142,7 @@ # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # Default primary key field type diff --git a/sdks/apigw-manager/demo/urls.py b/sdks/apigw-manager/demo/urls.py index ed8144ca..037275d7 100644 --- a/sdks/apigw-manager/demo/urls.py +++ b/sdks/apigw-manager/demo/urls.py @@ -9,11 +9,12 @@ specific language governing permissions and limitations under the License. """ -from demo import views from django.conf.urls import url +from demo import views + urlpatterns = [ - url(r'^test/jwt/?', views.jwt_info), - url(r'^test/app/?', views.jwt_app), - url(r'^test/user/?', views.jwt_user), + url(r"^test/jwt/?", views.jwt_info), + url(r"^test/app/?", views.jwt_app), + url(r"^test/user/?", views.jwt_user), ] diff --git a/sdks/apigw-manager/demo/views.py b/sdks/apigw-manager/demo/views.py index c25c0266..f811b413 100644 --- a/sdks/apigw-manager/demo/views.py +++ b/sdks/apigw-manager/demo/views.py @@ -14,7 +14,7 @@ def jwt_info(request): data = {} - jwt = getattr(request, 'jwt', None) + jwt = getattr(request, "jwt", None) if jwt: data.update( { @@ -28,7 +28,7 @@ def jwt_info(request): def jwt_app(request): data = {} - app = getattr(request, 'app', None) + app = getattr(request, "app", None) if app: data.update( { @@ -42,7 +42,7 @@ def jwt_app(request): def jwt_user(request): data = {} - user = getattr(request, 'user', None) + user = getattr(request, "user", None) if user: data.update( { diff --git a/sdks/apigw-manager/docs/sync-apigateway-with-django.md b/sdks/apigw-manager/docs/sync-apigateway-with-django.md new file mode 100644 index 00000000..9c5b72cc --- /dev/null +++ b/sdks/apigw-manager/docs/sync-apigateway-with-django.md @@ -0,0 +1,138 @@ +### 直接使用 Django Command 同步网关 + +项目安装 SDK apigw-manager 后,可以直接执行 SDK 提供的 Django Command。 +- 准备文件的样例 [examples/django/use-custom-script](../examples/django/use-custom-script) + +#### 步骤1. 准备自定义同步脚本 + +创建一个 bash 脚本,如 `sync-apigateway.sh`,使用 SDK 提供的 Django Command 定义网关配置的同步脚本,样例如下: +```shell +#!/bin/bash + +# 如果任何命令返回一个非零退出状态(错误),脚本将会立即终止执行 +set -e + +# 待同步网关名,需修改为实际网关名;直接指定网关名,则不需要配置 Django settings BK_APIGW_NAME +gateway_name="bk-demo" + +# 待同步网关、资源定义文件,需调整为实际的配置文件地址 +definition_file="support-files/definition.yaml" +resources_file="support-files/resources.yaml" + +echo "gateway sync definition start ..." +python manage.py sync_apigw_config --gateway-name=${gateway_name} --file="${definition_file}" # 同步网关基本信息 +python manage.py sync_apigw_stage --gateway-name=${gateway_name} --file="${definition_file}" # 同步网关环境信息 +python manage.py sync_apigw_resources --delete --gateway-name=${gateway_name} --file="${resources_file}" # 同步网关资源;--delete 将删除网关中未在 resources.yaml 存在的资源 +python manage.py sync_resource_docs_by_archive --gateway-name=${gateway_name} --file="${definition_file}" # 可选,同步资源文档 +python manage.py create_version_and_release_apigw --gateway-name=${gateway_name} --file="${definition_file}" # 创建资源版本并发布;指定参数 --generate-sdks 时,会同时生成资源版本对应的网关 SDK +python manage.py grant_apigw_permissions --gateway-name=${gateway_name} --file="${definition_file}" # 可选,为应用主动授权 +python manage.py fetch_apigw_public_key --gateway-name=${gateway_name} # 获取网关公钥 +echo "gateway sync definition end" +``` + +如果需要更灵活的控制,也可以采用自定义 Django Command 的方案,例如: +```python +from django.conf import settings +from django.core.management.base import BaseCommand +from django.core.management import call_command + + +class Command(BaseCommand): + def handle(self, *args, **kwargs): + if not getattr(settings, "SYNC_APIGATEWAY_ENABLED", True): + return + + # 待同步网关名,需修改为实际网关名;直接指定网关名,则不需要配置 Django settings BK_APIGW_NAME + gateway_name = "bk-demo" + + # 待同步网关、资源定义文件,需调整为实际的配置文件地址 + definition_path = "support-files/definition.yaml" + resources_path = "support-files/resources.yaml" + + call_command("sync_apigw_config", f"--gateway-name={gateway_name}", f"--file={definition_path}") + call_command("sync_apigw_stage", f"--gateway-name={gateway_name}", f"--file={definition_path}") + call_command("sync_apigw_resources", f"--gateway-name={gateway_name}", "--delete", f"--file={resources_path}") + call_command("sync_resource_docs_by_archive", f"--gateway-name={gateway_name}", f"--file={definition_path}") + call_command("create_version_and_release_apigw", f"--gateway-name={gateway_name}", f"--file={definition_path}") + call_command("grant_apigw_permissions", f"--gateway-name={gateway_name}", f"--file={definition_path}") + call_command("fetch_apigw_public_key", f"--gateway-name={gateway_name}") +``` + +#### 步骤2. 添加 SDK apigw-manager + +将 SDK apigw-manager 添加到项目依赖中,如 pyproject.toml 或 requirements.txt。 + +#### 步骤3. 将准备的网关配置文件,添加到项目 + +将准备的网关配置文件:definition.yaml, resources.yaml, apidocs (可选),添加到项目 + +#### 步骤4. 更新 Django settings 配置 + +在 Django settings.py 中定义网关名称和接口地址模板: + +```python +# 蓝鲸应用账号,用于访问网关 bk-apigateway 接口 +BK_APP_CODE = "my-app" +BK_APP_SECRET = "my-app-secret" + +# 待同步网关配置的网关名(如果需同步多个网关,可在同步命令中指定) +BK_APIGW_NAME = "my-gateway-name" + +# 需将 bkapi.example.com 替换为真实的云 API 域名; +# 在 PaaS 3.0 部署的应用,可从环境变量中获取 BK_API_URL_TMPL,不需要额外配置; +# 实际上,SDK 将调用网关 bk-apigateway 接口将数据同步到 API 网关 +BK_API_URL_TMPL = "http://bkapi.example.com/api/{api_name}/" +``` + +在 INSTALLED_APPS 中加入以下配置,SDK 将创建表 `apigw_manager_context` 用于存储一些中间数据: + +```python +INSTALLED_APPS += [ + "apigw_manager.apigw", +] +``` + +#### 步骤5. 同步网关数据到 API 网关 + +chart 部署方案,可采用 K8S Job 同步,样例如下: +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: "bk-demo-sync-apigateway" +spec: + template: + spec: + containers: + - command: + - bash + args: + - support-files/bin/sync-apigateway.sh + ## 自定义 Django Command 时,可直接执行 Command 指令 + # -c + # "python manage.py sync_apigateway" + image: "hub.bktencent.com/blueking/my-image:1.0.0" + imagePullPolicy: "IfNotPresent" + name: sync-apigateway +``` + +二进制部署方案,在部署阶段直接执行 sync-apigateway.sh 脚本: +```shell +bash support-files/bin/sync-apigateway.sh +``` + + +### 支持的 Django Command 列表 + +```bash +python manage.py add_related_apps --gateway-name=${gateway_name} --file="${definition_file}" # 可选,为网关添加关联应用,关联应用可以通过网关 bk-apigateway 提供的接口管理网关数据 +python manage.py apply_apigw_permissions --gateway-name=${gateway_name} --file="${definition_file}" # 可选,申请网关权限 +python manage.py create_version_and_release_apigw --gateway-name=${gateway_name} --file="${definition_file}" # 创建资源版本并发布;指定参数 --generate-sdks 时,会同时生成资源版本对应的网关 SDK +python manage.py fetch_apigw_public_key --gateway-name=${gateway_name} # 获取网关公钥 +python manage.py fetch_esb_public_key # 可选,获取 ESB 公钥(专用于同时接入 ESB 和网关的系统) +python manage.py grant_apigw_permissions --gateway-name=${gateway_name} --file="${definition_file}" # 可选,为应用主动授权 +python manage.py sync_apigw_config --gateway-name=${gateway_name} --file="${definition_file}" # 同步网关基本信息 +python manage.py sync_apigw_resources --delete --gateway-name=${gateway_name} --file="${resources_file}" # 同步网关资源;--delete 将删除网关中未在 resources.yaml 存在的资源 +python manage.py sync_apigw_stage --gateway-name=${gateway_name} --file="${definition_file}" # 同步网关环境信息 +python manage.py sync_resource_docs_by_archive --gateway-name=${gateway_name} --file="${definition_file}" # 可选,同步资源文档 +``` diff --git a/sdks/apigw-manager/docs/sync-apigateway-with-docker.md b/sdks/apigw-manager/docs/sync-apigateway-with-docker.md new file mode 100644 index 00000000..6e29e4d0 --- /dev/null +++ b/sdks/apigw-manager/docs/sync-apigateway-with-docker.md @@ -0,0 +1,268 @@ +## 通过镜像方式同步网关 + +网关提供基础镜像 apigw-manager,用于同步网关数据到 API 网关。基础镜像通过 [Dockerfile](../Dockerfile) 进行构建,该镜像封装了 [demo](../demo) 项目,可读取 /data/ 目录,直接进行网关注册和同步操作,目录约定: +- */data/definition.yaml*:网关定义文件,用于注册网关; +- */data/resources.yaml*:资源定义文件,用于同步网关资源,可通过网关导出; +- */data/apidocs*:文档目录,可通过网关导出后解压; +- */data/bin/sync-apigateway.sh*:自定义同步脚本;镜像提供默认同步脚本:[sync-apigateway.sh](../bin/sync-apigateway.sh),如不满足需求,可自定义同步脚本 + +镜像执行同步时,需要额外的环境变量支持: +- `BK_APIGW_NAME`:网关名称; +- `BK_API_URL_TMPL`:云网关 API 地址模板,例如:http://bkapi.example.com/api/{api_name}; +- `BK_APP_CODE`:应用名称; +- `BK_APP_SECRET`:应用密钥; + +通过镜像进行同步时,镜像需访问用户自定义的数据,在 chart 和二进制两种不同的部署方案中,镜像加载用户自定义数据的方式有所不同: +- chart: + - 单文件大小 < 1MB 时,可使用 ConfigMap 挂载 + - 单文件大小 >= 1MB 时,可创建自定义镜像 +- 二进制:可直接通过外部文件挂载 + +#### 准备工作 + +基础镜像提供了同步脚本 [sync-apigateway.sh](../bin/sync-apigateway.sh),脚本允许通过额外的环境变量设置命令参数: +- `SYNC_APIGW_CONFIG_ARGS`: 用于命令 `sync_apigw_config` +- `SYNC_APIGW_STAGE_ARGS`: 用于命令 `sync_apigw_stage` +- `APPLY_APIGW_PERMISSIONS_ARGS`: 用于命令 `apply_apigw_permissions` +- `GRANT_APIGW_PERMISSIONS_ARGS`: 用于命令 `grant_apigw_permissions` +- `SYNC_APIGW_RESOURCES_ARGS`: 默认值:"--delete",用于命令 `sync_apigw_resources` +- `SYNC_RESOURCE_DOCS_BY_ARCHIVE_ARGS`: 默认值: "--safe-mode",用于命令 `sync_resource_docs_by_archive` +- `CREATE_VERSION_AND_RELEASE_APIGW_ARGS`: 默认值:"--generate-sdks",用于命令 `create_version_and_release_apigw` + +如果基础镜像提供的同步脚本不满足需求,可以自定义同步脚本,镜像执行时指定使用自定义同步脚本即可。自定义同步脚本样例如下: +```bash +#!/bin/bash + +# 加载 apigw-manager 原始镜像中的通用函数 +source /apigw-manager/bin/functions.sh + +# 待同步网关名,需修改为实际网关名;直接指定网关名,则不需要配置环境变量 BK_APIGW_NAME +gateway_name="bk-demo" + +# 待同步网关、资源定义文件 +definition_file="/data/definition.yaml" +resources_file="/data/resources.yaml" + +title "begin to db migrate" +call_command_or_warning migrate apigw + +title "syncing apigateway" +call_definition_command_or_exit sync_apigw_config "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_stage "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_resources "${resources_file}" --gateway-name=${gateway_name} --delete +call_definition_command_or_exit sync_resource_docs_by_archive "${definition_file}" --gateway-name=${gateway_name} --safe-mode +call_definition_command_or_exit grant_apigw_permissions "${definition_file}" --gateway-name=${gateway_name} + +title "fetch apigateway public key" +apigw-manager.sh fetch_apigw_public_key --gateway-name=${gateway_name} --print > "apigateway.pub" + +title "releasing" +call_definition_command_or_exit create_version_and_release_apigw "${definition_file}" --gateway-name=${gateway_name} + +log_info "done" +``` + +基础镜像提供一些常用的 bash 函数,以及执行 Django Command 指令的辅助脚本: +- `functions.sh`,定义一些常用 bash 函数,源码 [functions.sh](../bin/functions.sh) +- `apigw-manager.sh`: 单纯执行一个 Django Command 指令,出错返回非 0 错误码,不退出脚本,源码 [apigw-manager.sh](../bin/apigw-manager.sh) + +functions.sh 中的 bash 函数: +- `call_command_or_warning`: 执行一个 Django Command 指令,出错返回非 0 错误码,不退出脚本 +- `call_definition_command_or_warning`: 执行一个 Django Command 指令,出错时打印告警日志,不退出脚本 +- `call_definition_command_or_exit`: 执行一个 Django Command 指令,出错退出脚本执行 +- `title`: 打印标题 +- `log_info`: 打印 info 日志 +- `log_warn`: 打印 warning 日志 +- `log_error`: 打印 error 日志 + +#### 使用方式一:chart + ConfigMap + +使用基础镜像 apigw-manager,并为网关配置、资源文档创建 ConfigMap 对象,将这些 ConfigMap 挂载到基础镜像中,如此镜像就可以读取到网关数据,但是 chart 本身限制单文件不能超过 1MB。 +- 准备文件的样例 [examples/chart/use-configmap](../examples/chart/use-configmap) + +操作步骤如下: + +步骤1:将网关配置、资源文档、自定义同步命令,放到 chart 项目的 files 文件夹下,可参考目录: +``` +. +├── Chart.yaml +├── files +│   └── support-files +│   ├── apidocs +│   │   ├── en +│   │   │   └── anything.md +│   │   └── zh +│   │   └── anything.md +│   ├── bin +│   │   └── sync-apigateway.sh +│   ├── definition.yaml +│   └── resources.yaml +``` + +步骤2:在 chart values.yaml 中添加配置 +```yaml +apigatewaySync: + image: "hub.bktencent.com/blueking/apigw-manager:latest" + configMapMounts: + - name: "sync-apigw-base" + filePath: "files/support-files/*" + mountPath: "/data/" + - name: "sync-apigw-bin" + filePath: "files/support-files/bin/*" + mountPath: "/data/bin/" + - name: "sync-apigw-apidocs-zh" + filePath: "files/support-files/apidocs/zh/*" + mountPath: "/data/apidocs/zh/" + - name: "sync-apigw-apidocs-en" + filePath: "files/support-files/apidocs/en/*" + mountPath: "/data/apidocs/en/" + extraEnvVars: + - name: BK_APIGW_NAME + value: "bk-demo" + - name: BK_APP_CODE + value: "bk-demo" + - name: BK_APP_SECRET + value: "secret" + - name: BK_API_URL_TMPL + value: "http://bkapi.example.com/api/{api_name}" +``` + +步骤2:在 chart templates 下创建 ConfigMap 模板文件,样例如下: +```yaml +{{- $files := .Files }} +{{- range $item := .Values.apigatewaySync.configMapMounts }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: bk-demo-{{ $item.name }} +data: +{{ ($files.Glob $item.filePath).AsConfig | indent 2 }} +{{- end }} +``` + +步骤3:添加 K8S Job 同步任务,样例如下: +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: "bk-demo-sync-apigateway" +spec: + template: + spec: + containers: + - command: + - bash + args: + - bin/sync-apigateway.sh + image: "{{ .Values.apigatewaySync.image }}" + imagePullPolicy: "Always" + name: sync-apigateway + env: + {{- toYaml .Values.apigatewaySync.extraEnvVars | nindent 8 }} + volumeMounts: + {{- range $item := .Values.apigatewaySync.configMapMounts }} + - mountPath: "{{ $item.mountPath }}" + name: "{{ $item.name }}" + {{- end }} + volumes: + {{- range $item := .Values.apigatewaySync.configMapMounts }} + - name: "{{ $item.name }}" + configMap: + defaultMode: 420 + name: "{{ $item.name }}" + {{- end }} + restartPolicy: Never +``` + +#### 使用方式二:chart + 自定义镜像 + +可将 apigw-manager 作为基础镜像,将配置文件和文档一并构建成一个新镜像,然后通过如 K8S Job 方式进行同步。 +- 准备文件的样例 [examples/chart/use-custom-docker-image](../examples/chart/use-custom-docker-image) + +操作步骤如下: + +步骤1. 将网关配置,资源文档,自定义同步命令,放到一个文件夹下,可参考目录: +``` +. +├── Dockerfile +└── support-files + ├── apidocs + │   ├── en + │   │   └── anything.md + │   └── zh + │   └── anything.md + ├── bin + │   └── sync-apigateway.sh + ├── definition.yaml + └── resources.yaml +``` + +步骤2. 构建 Dockerfile,参考: +```Dockerfile +FROM hub.bktencent.com/blueking/apigw-manager:latest + +COPY support-files /data/ +``` + +步骤3:构建新镜像 +```shell +docker build -t my-apigw-manager -f Dockerfile . +``` + +步骤4:添加 K8S Job 同步任务,样例如下 +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: "bk-demo-sync-apigateway" +spec: + template: + spec: + containers: + - command: + - bash + args: + - bin/sync-apigateway.sh + image: "hub.bktencent.com/blueking/my-apigw-manager:latest" + imagePullPolicy: "Always" + name: sync-apigateway + env: + - name: BK_APIGW_NAME + value: "bk-demo" + - name: BK_APP_CODE + value: "bk-demo" + - name: BK_APP_SECRET + value: "secret" + - name: BK_API_URL_TMPL + value: "http://bkapi.example.com/api/{api_name}" + restartPolicy: Never +``` + +#### 使用方式三:二进制 + 外部文件挂载 + +使用基础镜像 apigw-manager,通过外部文件挂载的方式,将对应的目录挂载到 /data/ 目录下,可通过以下类似的命令进行同步: +```bash +docker run --rm \ + -v //:/data/ \ + -e BK_APIGW_NAME= \ + -e BK_API_URL_TMPL= \ + -e BK_APP_CODE= \ + -e BK_APP_SECRET= \ + hub.bktencent.com/blueking/apigw-manager:latest +``` + + +### 支持同步指令 + +```bash +call_definition_command_or_exit add_related_apps "${definition_file}" --gateway-name=${gateway_name} # 可选,为网关添加关联应用,关联应用可以通过网关 bk-apigateway 提供的接口管理网关数据 +call_definition_command_or_exit apply_apigw_permissions "${definition_file}" --gateway-name=${gateway_name} # 可选,申请网关权限 +call_definition_command_or_exit create_version_and_release_apigw "${definition_file}" --gateway-name=${gateway_name} # 创建资源版本并发布;指定参数 --generate-sdks 时,会同时生成资源版本对应的网关 SDK +apigw-manager.sh fetch_apigw_public_key --gateway-name=${gateway_name} --print > "apigateway.pub" # 获取网关公钥,存放到文件 apigateway.pub +call_definition_command_or_exit grant_apigw_permissions "${definition_file}" --gateway-name=${gateway_name} # 可选,为应用主动授权 +call_definition_command_or_exit sync_apigw_config "${definition_file}" --gateway-name=${gateway_name} # 同步网关基本信息 +call_definition_command_or_exit sync_apigw_resources "${resources_file}" --gateway-name=${gateway_name} --delete # 同步网关资源;--delete 将删除网关中未在 resources.yaml 存在的资源 +call_definition_command_or_exit sync_apigw_stage "${definition_file}" --gateway-name=${gateway_name} # 同步网关环境信息 +call_definition_command_or_exit sync_resource_docs_by_archive "${definition_file}" --gateway-name=${gateway_name} --safe-mode # 可选,同步资源文档 +``` diff --git a/sdks/apigw-manager/examples/chart/use-configmap/Chart.yaml b/sdks/apigw-manager/examples/chart/use-configmap/Chart.yaml new file mode 100644 index 00000000..1dc73635 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/Chart.yaml @@ -0,0 +1,6 @@ +name: bk-demo +apiVersion: v2 +description: Just for test +type: application +version: 1.0.0 +appVersion: 1.0.0 \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-configmap/README.md b/sdks/apigw-manager/examples/chart/use-configmap/README.md new file mode 100644 index 00000000..50e14fac --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/README.md @@ -0,0 +1,5 @@ +# 通过镜像方式同步网关: chart + ConfigMap 样例 + +主要步骤: +- 1. 修改 values.yaml 中的 `apigatewaySync.extraEnvVars` +- 2. 安装 chart,例如: `helm install bk-demo . -n blueking` \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/en/anything.md b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/en/anything.md new file mode 100644 index 00000000..63a4d8fd --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/en/anything.md @@ -0,0 +1,29 @@ +### Description + +This is a description + +### Parameters + +| Name | Type | Required | Description | +| ---- | ------ | -------- | ------------- | +| foo | string | No | This is a foo | + +### Request Example +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### Response Example +```python +{ + "method": "GET" +} +``` + +### Response Parameters +| Name | Type | Description | +| ------ | ------ | -------------- | +| method | string | request method | diff --git a/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/zh/anything.md b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/zh/anything.md new file mode 100644 index 00000000..da285457 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/apidocs/zh/anything.md @@ -0,0 +1,29 @@ +### 描述 + +这是一个描述 + +### 输入参数 +| 参数名称 | 参数类型 | 必选 | 描述 | +| -------- | -------- | ---- | ------------- | +| foo | string | No | This is a foo | + + +### 调用示例 +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### 响应示例 +```python +{ + "method": "GET" +} +``` + +### 响应参数说明 +| 参数名称 | 参数类型 | 描述 | +| -------- | -------- | -------------- | +| method | string | request method | \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/bin/sync-apigateway.sh b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/bin/sync-apigateway.sh new file mode 100755 index 00000000..08922fc3 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/bin/sync-apigateway.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# 加载 apigw-manager 原始镜像中的通用函数 +source /apigw-manager/bin/functions.sh + +# 待同步网关名 +gateway_name="bk-demo" + +# 待同步网关、资源定义文件 +definition_file="/data/definition.yaml" +resources_file="/data/resources.yaml" + +title "begin to db migrate" +call_command_or_warning migrate apigw + +title "syncing apigateway" +call_definition_command_or_exit sync_apigw_config "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_stage "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_resources "${resources_file}" --gateway-name=${gateway_name} --delete +call_definition_command_or_exit sync_resource_docs_by_archive "${definition_file}" --gateway-name=${gateway_name} --safe-mode +call_definition_command_or_exit grant_apigw_permissions "${definition_file}" --gateway-name=${gateway_name} + +title "fetch apigateway public key" +apigw-manager.sh fetch_apigw_public_key --gateway-name=${gateway_name} --print > "/tmp/apigateway.pub" + +title "releasing" +call_definition_command_or_exit create_version_and_release_apigw "${definition_file}" --gateway-name=${gateway_name} + +title "done" diff --git a/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/definition.yaml b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/definition.yaml new file mode 100644 index 00000000..d982d7ef --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/definition.yaml @@ -0,0 +1,41 @@ +spec_version: 1 + +release: + # 发布版本号 + version: 1.0.0 + title: "这是一个测试" + comment: "这是一个测试" + +apigateway: + description: "这是一个测试" + description_en: "This is a test" + is_public: false + maintainers: + - "admin" + +stage: + name: "prod" + description: "这是一个测试" + description_en: "This is a test" + proxy_http: + timeout: 60 + upstreams: + loadbalance: "roundrobin" + hosts: + - host: "https://httpbin.org" + weight: 100 + +# 资源文档 +# 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档: +# ./ +# - en +# - anything.md +# - zh +# - anything.md +resource_docs: + basedir: "/data/apidocs/" + +# 主动授权,网关主动给应用,添加访问网关所有资源的权限 +grant_permissions: + - bk_app_code: "{{ settings.BK_APP_CODE }}" + grant_dimension: "gateway" diff --git a/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/resources.yaml b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/resources.yaml new file mode 100644 index 00000000..1435567e --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/files/support-files/resources.yaml @@ -0,0 +1,34 @@ +swagger: '2.0' +basePath: / +info: + version: '0.1' + title: API Gateway Resources + description: '' +schemes: +- http +paths: + /anything: + get: + operationId: anything + description: '' + tags: [] + responses: + default: + description: '' + x-bk-apigateway-resource: + isPublic: false + allowApplyPermission: false + matchSubpath: false + backend: + type: HTTP + method: get + path: /anything + matchSubpath: false + timeout: 0 + upstreams: {} + transformHeaders: {} + authConfig: + appVerifiedRequired: true + userVerifiedRequired: false + resourcePermissionRequired: false + descriptionEn: diff --git a/sdks/apigw-manager/examples/chart/use-configmap/templates/_helpers.tpl b/sdks/apigw-manager/examples/chart/use-configmap/templates/_helpers.tpl new file mode 100644 index 00000000..9649dcde --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/templates/_helpers.tpl @@ -0,0 +1,65 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "bk-demo.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "bk-demo.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create a default name prefix for the resources which truncate at 32 chars. +*/}} +{{- define "bk-demo.name-prefix" -}} +{{- include "bk-demo.fullname" . | trunc 32 | trimSuffix "-" -}} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "bk-demo.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "bk-demo.labels" -}} +app.kubernetes.io/name: {{ include "bk-demo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +helm.sh/chart: {{ include "bk-demo.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "bk-demo.selector-labels" -}} +app.kubernetes.io/name: {{ include "bk-demo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create a job name with default prefix and release revision. +*/}} +{{- define "bk-demo.job-name" -}} +{{- $root := first . -}} +{{- $name := last . -}} +{{- include "bk-demo.name-prefix" $root }}-{{ $name }}-{{ $root.Release.Revision }} +{{- end }} \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-configmap.yaml b/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-configmap.yaml new file mode 100644 index 00000000..0c0222e9 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-configmap.yaml @@ -0,0 +1,15 @@ +{{- if .Values.apigatewaySync.enabled }} +{{- $files := .Files }} +{{- $name_prefix := include "bk-demo.name-prefix" . }} +{{- $labels := include "bk-demo.labels" . }} +{{- range $item := .Values.apigatewaySync.configMapMounts }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $name_prefix }}-{{ $item.name }} + labels: {{ $labels | nindent 4 }} +data: +{{ ($files.Glob $item.filePath).AsConfig | indent 2 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-job.yaml b/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-job.yaml new file mode 100644 index 00000000..1ea2468c --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/templates/sync-apigateway-job.yaml @@ -0,0 +1,39 @@ +{{- if .Values.apigatewaySync.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "bk-demo.job-name" (list . "sync-apigateway") }} + labels: {{ include "bk-demo.labels" . | nindent 4 }} +spec: + backoffLimit: 10 + parallelism: 1 + template: + metadata: + labels: {{ include "bk-demo.selector-labels" . | nindent 8 }} + app.kubernetes.io/component: "sync-apigateway" + spec: + containers: + - command: + - bash + args: + - bin/sync-apigateway.sh + image: "{{ .Values.apigatewaySync.image }}" + imagePullPolicy: "Always" + name: sync-apigateway + env: + {{- toYaml .Values.apigatewaySync.extraEnvVars | nindent 8 }} + volumeMounts: + {{- range $item := .Values.apigatewaySync.configMapMounts }} + - mountPath: "{{ $item.mountPath }}" + name: "{{ $item.name }}" + {{- end }} + volumes: + {{- $name_prefix := include "bk-demo.name-prefix" . }} + {{- range $item := .Values.apigatewaySync.configMapMounts }} + - name: "{{ $item.name }}" + configMap: + defaultMode: 420 + name: "{{ $name_prefix }}-{{ $item.name }}" + {{- end }} + restartPolicy: Never +{{- end }} diff --git a/sdks/apigw-manager/examples/chart/use-configmap/values.yaml b/sdks/apigw-manager/examples/chart/use-configmap/values.yaml new file mode 100644 index 00000000..d92e1db8 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-configmap/values.yaml @@ -0,0 +1,25 @@ +apigatewaySync: + enabled: true + image: "hub.bktencent.com/blueking/apigw-manager:latest" + configMapMounts: + - name: "sync-apigw-base" + filePath: "files/support-files/*" + mountPath: "/data/" + - name: "sync-apigw-bin" + filePath: "files/support-files/bin/*" + mountPath: "/data/bin/" + - name: "sync-apigw-apidocs-zh" + filePath: "files/support-files/apidocs/zh/*" + mountPath: "/data/apidocs/zh/" + - name: "sync-apigw-apidocs-en" + filePath: "files/support-files/apidocs/en/*" + mountPath: "/data/apidocs/en/" + extraEnvVars: + - name: BK_APIGW_NAME + value: "bk-demo" + - name: BK_APP_CODE + value: "bk-demo" + - name: BK_APP_SECRET + value: "secret" + - name: BK_API_URL_TMPL + value: "http://bkapi.example.com/api/{api_name}" \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/README.md b/sdks/apigw-manager/examples/chart/use-custom-docker-image/README.md new file mode 100644 index 00000000..2180495e --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/README.md @@ -0,0 +1,10 @@ +# 通过镜像方式同步网关:chart + 自定义镜像样例 + +文件目录: +- my-apigw-manager: 用于生成自定义镜像 +- bk-demo-chart: chart 样例,使用生成的自定义镜像同步网关 + +主要步骤: +- 1. 构建自定义镜像,例如:`docker build -f my-apigw-manager/Dockerfile --tag my-apigw-manager:development my-apigw-manager` +- 2. 修改 bk-demo-chart/values.yaml 中的 `apigatewaySync.image`, `apigatewaySync.extraEnvVars` +- 3. 安装 chart,例如:`helm install bk-demo-chart bk-demo-chart -f bk-demo-chart/values.yaml -n blueking` \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/Chart.yaml b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/Chart.yaml new file mode 100644 index 00000000..1dc73635 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/Chart.yaml @@ -0,0 +1,6 @@ +name: bk-demo +apiVersion: v2 +description: Just for test +type: application +version: 1.0.0 +appVersion: 1.0.0 \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/_helpers.tpl b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/_helpers.tpl new file mode 100644 index 00000000..9649dcde --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/_helpers.tpl @@ -0,0 +1,65 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "bk-demo.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "bk-demo.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create a default name prefix for the resources which truncate at 32 chars. +*/}} +{{- define "bk-demo.name-prefix" -}} +{{- include "bk-demo.fullname" . | trunc 32 | trimSuffix "-" -}} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "bk-demo.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "bk-demo.labels" -}} +app.kubernetes.io/name: {{ include "bk-demo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +helm.sh/chart: {{ include "bk-demo.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "bk-demo.selector-labels" -}} +app.kubernetes.io/name: {{ include "bk-demo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create a job name with default prefix and release revision. +*/}} +{{- define "bk-demo.job-name" -}} +{{- $root := first . -}} +{{- $name := last . -}} +{{- include "bk-demo.name-prefix" $root }}-{{ $name }}-{{ $root.Release.Revision }} +{{- end }} \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/sync-apigateway-job.yaml b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/sync-apigateway-job.yaml new file mode 100644 index 00000000..8343e847 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/templates/sync-apigateway-job.yaml @@ -0,0 +1,26 @@ +{{- if .Values.apigatewaySync.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "bk-demo.job-name" (list . "sync-apigateway") }} + labels: {{ include "bk-demo.labels" . | nindent 4 }} +spec: + backoffLimit: 10 + parallelism: 1 + template: + metadata: + labels: {{ include "bk-demo.selector-labels" . | nindent 8 }} + app.kubernetes.io/component: "sync-apigateway" + spec: + containers: + - command: + - bash + args: + - bin/sync-apigateway.sh + image: "{{ .Values.apigatewaySync.image }}" + imagePullPolicy: "Always" + name: sync-apigateway + env: + {{- toYaml .Values.apigatewaySync.extraEnvVars | nindent 8 }} + restartPolicy: Never +{{- end }} \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/values.yaml b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/values.yaml new file mode 100644 index 00000000..073d7497 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/bk-demo-chart/values.yaml @@ -0,0 +1,12 @@ +apigatewaySync: + enabled: true + image: "hub.bktencent.com/blueking/my-apigw-manager:latest" + extraEnvVars: + - name: BK_APIGW_NAME + value: "bk-demo" + - name: BK_APP_CODE + value: "bk-demo" + - name: BK_APP_SECRET + value: "secret" + - name: BK_API_URL_TMPL + value: "http://bkapi.example.com/api/{api_name}" \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/Dockerfile b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/Dockerfile new file mode 100644 index 00000000..ad9210d1 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/Dockerfile @@ -0,0 +1,3 @@ +FROM hub.bktencent.com/blueking/apigw-manager:latest + +COPY support-files /data/ \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/en/anything.md b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/en/anything.md new file mode 100644 index 00000000..63a4d8fd --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/en/anything.md @@ -0,0 +1,29 @@ +### Description + +This is a description + +### Parameters + +| Name | Type | Required | Description | +| ---- | ------ | -------- | ------------- | +| foo | string | No | This is a foo | + +### Request Example +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### Response Example +```python +{ + "method": "GET" +} +``` + +### Response Parameters +| Name | Type | Description | +| ------ | ------ | -------------- | +| method | string | request method | diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/zh/anything.md b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/zh/anything.md new file mode 100644 index 00000000..da285457 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/apidocs/zh/anything.md @@ -0,0 +1,29 @@ +### 描述 + +这是一个描述 + +### 输入参数 +| 参数名称 | 参数类型 | 必选 | 描述 | +| -------- | -------- | ---- | ------------- | +| foo | string | No | This is a foo | + + +### 调用示例 +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### 响应示例 +```python +{ + "method": "GET" +} +``` + +### 响应参数说明 +| 参数名称 | 参数类型 | 描述 | +| -------- | -------- | -------------- | +| method | string | request method | \ No newline at end of file diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/bin/sync-apigateway.sh b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/bin/sync-apigateway.sh new file mode 100755 index 00000000..d4a124a7 --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/bin/sync-apigateway.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# 加载 apigw-manager 原始镜像中的通用函数 +source /apigw-manager/bin/functions.sh + +# 待同步网关名 +gateway_name="bk-demo" + +# 待同步网关、资源定义文件 +definition_file="/data/definition.yaml" +resources_file="/data/resources.yaml" + +title "begin to db migrate" +call_command_or_warning migrate apigw + +title "syncing apigateway" +call_definition_command_or_exit sync_apigw_config "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_stage "${definition_file}" --gateway-name=${gateway_name} +call_definition_command_or_exit sync_apigw_resources "${resources_file}" --gateway-name=${gateway_name} --delete +call_definition_command_or_exit sync_resource_docs_by_archive "${definition_file}" --gateway-name=${gateway_name} --safe-mode +call_definition_command_or_exit grant_apigw_permissions "${definition_file}" --gateway-name=${gateway_name} + +title "fetch apigateway public key" +apigw-manager.sh fetch_apigw_public_key --gateway-name=${gateway_name} --print > "apigateway.pub" + +title "releasing" +call_definition_command_or_exit create_version_and_release_apigw "${definition_file}" --gateway-name=${gateway_name} + +title "done" diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/definition.yaml b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/definition.yaml new file mode 100644 index 00000000..d982d7ef --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/definition.yaml @@ -0,0 +1,41 @@ +spec_version: 1 + +release: + # 发布版本号 + version: 1.0.0 + title: "这是一个测试" + comment: "这是一个测试" + +apigateway: + description: "这是一个测试" + description_en: "This is a test" + is_public: false + maintainers: + - "admin" + +stage: + name: "prod" + description: "这是一个测试" + description_en: "This is a test" + proxy_http: + timeout: 60 + upstreams: + loadbalance: "roundrobin" + hosts: + - host: "https://httpbin.org" + weight: 100 + +# 资源文档 +# 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档: +# ./ +# - en +# - anything.md +# - zh +# - anything.md +resource_docs: + basedir: "/data/apidocs/" + +# 主动授权,网关主动给应用,添加访问网关所有资源的权限 +grant_permissions: + - bk_app_code: "{{ settings.BK_APP_CODE }}" + grant_dimension: "gateway" diff --git a/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/resources.yaml b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/resources.yaml new file mode 100644 index 00000000..1435567e --- /dev/null +++ b/sdks/apigw-manager/examples/chart/use-custom-docker-image/my-apigw-manager/support-files/resources.yaml @@ -0,0 +1,34 @@ +swagger: '2.0' +basePath: / +info: + version: '0.1' + title: API Gateway Resources + description: '' +schemes: +- http +paths: + /anything: + get: + operationId: anything + description: '' + tags: [] + responses: + default: + description: '' + x-bk-apigateway-resource: + isPublic: false + allowApplyPermission: false + matchSubpath: false + backend: + type: HTTP + method: get + path: /anything + matchSubpath: false + timeout: 0 + upstreams: {} + transformHeaders: {} + authConfig: + appVerifiedRequired: true + userVerifiedRequired: false + resourcePermissionRequired: false + descriptionEn: diff --git a/sdks/apigw-manager/examples/django/use-custom-script/README.md b/sdks/apigw-manager/examples/django/use-custom-script/README.md new file mode 100644 index 00000000..80a48146 --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/README.md @@ -0,0 +1,8 @@ +# 直接使用 Django Command 同步网关样例 + +主要步骤: +- 1. 提供一个 Django 项目,并参考 [直接使用 Django Command 同步网关](../../../docs/sync-apigateway-with-django.md),将 SDK apigw-manager 添加到项目 +- 2. 打包项目镜像时,将 `support-files` 拷贝到该项目根目录 +- 3. 执行同步任务: + - chart 部署时,采用 K8S Job 同步;在 Job 中,执行 `bash support-files/bin/sync-apigateway.sh` + - 二进制部署时,直接执行 `bash support-files/bin/sync-apigateway.sh` \ No newline at end of file diff --git a/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/en/anything.md b/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/en/anything.md new file mode 100644 index 00000000..63a4d8fd --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/en/anything.md @@ -0,0 +1,29 @@ +### Description + +This is a description + +### Parameters + +| Name | Type | Required | Description | +| ---- | ------ | -------- | ------------- | +| foo | string | No | This is a foo | + +### Request Example +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### Response Example +```python +{ + "method": "GET" +} +``` + +### Response Parameters +| Name | Type | Description | +| ------ | ------ | -------------- | +| method | string | request method | diff --git a/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/zh/anything.md b/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/zh/anything.md new file mode 100644 index 00000000..da285457 --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/support-files/apidocs/zh/anything.md @@ -0,0 +1,29 @@ +### 描述 + +这是一个描述 + +### 输入参数 +| 参数名称 | 参数类型 | 必选 | 描述 | +| -------- | -------- | ---- | ------------- | +| foo | string | No | This is a foo | + + +### 调用示例 +```python +from bkapi.bk_demo.shortcuts import get_client_by_request + +client = get_client_by_request(request) +result = client.api.anything({"foo": "bar"}, path_params={}, headers=None, verify=True) +``` + +### 响应示例 +```python +{ + "method": "GET" +} +``` + +### 响应参数说明 +| 参数名称 | 参数类型 | 描述 | +| -------- | -------- | -------------- | +| method | string | request method | \ No newline at end of file diff --git a/sdks/apigw-manager/examples/django/use-custom-script/support-files/bin/sync-apigateway.sh b/sdks/apigw-manager/examples/django/use-custom-script/support-files/bin/sync-apigateway.sh new file mode 100755 index 00000000..6e5d23da --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/support-files/bin/sync-apigateway.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# 注意事项: +# - 需将 "apigw_manager.apigw" 添加到 django settings INSTALLED_APPS +# - 需提前执行 "python manage.py migrate" + +# 如果任何命令返回一个非零退出状态(错误),脚本将会立即终止执行 +set -e + +# 待同步网关名,直接指定网关名,则不需要配置 django settings BK_APIGW_NAME +gateway_name="bk-demo" + +# 待同步网关、资源定义文件 +definition_file="support-files/definition.yaml" +resources_file="support-files/resources.yaml" + +# sync gateway +echo "gateway ${gateway_name} sync definition start ..." +python manage.py sync_apigw_config --gateway-name=${gateway_name} --file="${definition_file}" +python manage.py sync_apigw_stage --gateway-name=${gateway_name} --file="${definition_file}" +python manage.py sync_apigw_resources --delete --gateway-name=${gateway_name} --file="${resources_file}" +python manage.py sync_resource_docs_by_archive --gateway-name=${gateway_name} --file="${definition_file}" +python manage.py create_version_and_release_apigw --gateway-name=${gateway_name} --file="${definition_file}" +python manage.py grant_apigw_permissions --gateway-name=${gateway_name} --file="${definition_file}" +python manage.py fetch_apigw_public_key --gateway-name=${gateway_name} +echo "gateway ${gateway_name} sync definition end" diff --git a/sdks/apigw-manager/examples/django/use-custom-script/support-files/definition.yaml b/sdks/apigw-manager/examples/django/use-custom-script/support-files/definition.yaml new file mode 100644 index 00000000..5e1ec639 --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/support-files/definition.yaml @@ -0,0 +1,41 @@ +spec_version: 1 + +release: + # 发布版本号 + version: 1.0.0 + title: "这是一个测试" + comment: "这是一个测试" + +apigateway: + description: "这是一个测试" + description_en: "This is a test" + is_public: false + maintainers: + - "admin" + +stage: + name: "prod" + description: "这是一个测试" + description_en: "This is a test" + proxy_http: + timeout: 60 + upstreams: + loadbalance: "roundrobin" + hosts: + - host: "https://httpbin.org" + weight: 100 + +# 资源文档 +# 资源文档的目录格式样例如下,en 为英文文档,zh 为中文文档: +# ./ +# - en +# - anything.md +# - zh +# - anything.md +resource_docs: + basedir: "support-files/apidocs/" + +# 主动授权,网关主动给应用,添加访问网关所有资源的权限 +grant_permissions: + - bk_app_code: "{{ settings.BK_APP_CODE }}" + grant_dimension: "gateway" diff --git a/sdks/apigw-manager/examples/django/use-custom-script/support-files/resources.yaml b/sdks/apigw-manager/examples/django/use-custom-script/support-files/resources.yaml new file mode 100644 index 00000000..1435567e --- /dev/null +++ b/sdks/apigw-manager/examples/django/use-custom-script/support-files/resources.yaml @@ -0,0 +1,34 @@ +swagger: '2.0' +basePath: / +info: + version: '0.1' + title: API Gateway Resources + description: '' +schemes: +- http +paths: + /anything: + get: + operationId: anything + description: '' + tags: [] + responses: + default: + description: '' + x-bk-apigateway-resource: + isPublic: false + allowApplyPermission: false + matchSubpath: false + backend: + type: HTTP + method: get + path: /anything + matchSubpath: false + timeout: 0 + upstreams: {} + transformHeaders: {} + authConfig: + appVerifiedRequired: true + userVerifiedRequired: false + resourcePermissionRequired: false + descriptionEn: diff --git a/sdks/apigw-manager/mypy.ini b/sdks/apigw-manager/mypy.ini deleted file mode 100644 index 3a7939f5..00000000 --- a/sdks/apigw-manager/mypy.ini +++ /dev/null @@ -1,7 +0,0 @@ -[mypy] -ignore_missing_imports = True -show_error_codes = True - -[mypy-*.migrations.*,migrations.*] -# Django migrations should not produce any errors -ignore_errors = True diff --git a/sdks/apigw-manager/poetry.lock b/sdks/apigw-manager/poetry.lock index b3c813c5..35698010 100644 --- a/sdks/apigw-manager/poetry.lock +++ b/sdks/apigw-manager/poetry.lock @@ -1,26 +1,26 @@ -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = "*" +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "appnope" version = "0.1.2" description = "Disable App Nap on macOS >= 10.9" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, + {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, +] [[package]] name = "asgiref" version = "3.4.1" description = "ASGI specs, helper code, and adapters" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, + {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, +] [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.8\""} @@ -32,50 +32,51 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] name = "atomicwrites" version = "1.4.0" description = "Atomic file writes." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] [[package]] name = "attrs" version = "21.2.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] [package.extras] dev = ["coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"] - -[[package]] -name = "autoflake" -version = "1.4" -description = "Removes unused imports and unused variables" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -pyflakes = ">=1.1.0" +tests-no-zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"] [[package]] name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] [[package]] name = "backports.entry-points-selectable" version = "1.1.0" description = "Compatibility shim providing selectable entry points for older implementations" -category = "dev" optional = false python-versions = ">=2.7" +files = [ + {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, + {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, +] [package.dependencies] importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} @@ -88,9 +89,11 @@ testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4) name = "bkapi-bk-apigateway" version = "1.0.11" description = "蓝鲸API网关" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,<4.0,>=2.7" +files = [ + {file = "bkapi-bk-apigateway-1.0.11.tar.gz", hash = "sha256:fcdbc4eca8bfd3310995cec532ae127ee0533ea858c82916d9782e4df3df4c49"}, +] [package.dependencies] bkapi-client-core = ">=1.0.2,<2.0.0" @@ -100,50 +103,34 @@ django = ["bkapi-client-core[django] (>=1.0.2,<2.0.0)"] [[package]] name = "bkapi-client-core" -version = "1.1.3" -description = "" -category = "main" +version = "1.2.0" +description = "A toolkit for buiding blueking API clients." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "bkapi_client_core-1.2.0-py2.py3-none-any.whl", hash = "sha256:f18b29e0fc0ee8d5eca33ea1f823f26dc7d7adc2f39670cc45cc2f8452f39630"}, +] [package.dependencies] curlify = ">=2.0" requests = ">=2.20" +six = "*" typing-extensions = ">=3.7.4" [package.extras] -django = ["bkoauth (>=0.0.10)"] - -[[package]] -name = "black" -version = "20.8b1" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -appdirs = "*" -click = ">=7.1.2" -dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} -mypy-extensions = ">=0.4.3" -pathspec = ">=0.6,<1" -regex = ">=2020.1.8" -toml = ">=0.10.1" -typed-ast = ">=1.4.0" -typing-extensions = ">=3.7.4" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] +django = ["bkoauth (>=0.0.10)", "prometheus-client (>=0.9.0)"] +monitor = ["prometheus-client (>=0.9.0)"] [[package]] name = "bleach" version = "3.3.0" description = "An easy safelist-based HTML-sanitizing tool." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "bleach-3.3.0-py2.py3-none-any.whl", hash = "sha256:6123ddc1052673e52bab52cdc955bcb57a015264a1c57d37bea2f6b817af0125"}, + {file = "bleach-3.3.0.tar.gz", hash = "sha256:98b3170739e5e83dd9dc19633f074727ad848cbedb6026708c8ac2d3b697a433"}, +] [package.dependencies] packaging = "*" @@ -154,25 +141,77 @@ webencodings = "*" name = "cachetools" version = "4.2.4" description = "Extensible memoizing collections and decorators" -category = "main" optional = false python-versions = "~=3.5" +files = [ + {file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"}, + {file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"}, +] [[package]] name = "certifi" version = "2021.5.30" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = "*" +files = [ + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, +] [[package]] name = "cffi" version = "1.14.6" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" +files = [ + {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, + {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, + {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, + {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, + {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, + {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, + {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, + {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, + {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, + {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, + {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, + {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, + {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, + {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, + {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, + {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, + {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, + {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, +] [package.dependencies] pycparser = "*" @@ -181,48 +220,115 @@ pycparser = "*" name = "cfgv" version = "3.3.0" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"}, + {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"}, +] [[package]] name = "charset-normalizer" version = "2.0.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.5.0" +files = [ + {file = "charset-normalizer-2.0.1.tar.gz", hash = "sha256:ad0da505736fc7e716a8da15bf19a985db21ac6415c26b34d2fafd3beb3d927e"}, + {file = "charset_normalizer-2.0.1-py3-none-any.whl", hash = "sha256:b68b38179052975093d71c1b5361bf64afd80484697c1f27056e50593e695ceb"}, +] [package.extras] -unicode_backport = ["unicodedata2"] - -[[package]] -name = "click" -version = "8.0.1" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +unicode-backport = ["unicodedata2"] [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] + +[[package]] +name = "commonmark" +version = "0.9.1" +description = "Python parser for the CommonMark Markdown spec" +optional = false +python-versions = "*" +files = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, +] + +[package.extras] +test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "coverage" version = "5.5" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +files = [ + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, +] + +[package.dependencies] +toml = {version = "*", optional = true, markers = "extra == \"toml\""} [package.extras] toml = ["toml"] @@ -231,9 +337,24 @@ toml = ["toml"] name = "cryptography" version = "3.4.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"}, + {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"}, + {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"}, + {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"}, + {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"}, + {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"}, + {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b01fd6f2737816cb1e08ed4807ae194404790eac7ad030b34f2ce72b332f5586"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"}, + {file = "cryptography-3.4.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bf40af59ca2465b24e54f671b2de2c59257ddc4f7e5706dbd6930e26823668d3"}, + {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, +] [package.dependencies] cffi = ">=1.12" @@ -250,44 +371,47 @@ test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.0)" name = "curlify" version = "2.2.1" description = "Library to convert python requests object to curl command." -category = "main" optional = false python-versions = "*" +files = [ + {file = "curlify-2.2.1.tar.gz", hash = "sha256:0d3f02e7235faf952de8ef45ef469845196d30632d5838bcd5aee217726ddd6d"}, +] [package.dependencies] requests = "*" -[[package]] -name = "dataclasses" -version = "0.8" -description = "A backport of the dataclasses module for Python 3.6" -category = "dev" -optional = false -python-versions = ">=3.6, <3.7" - [[package]] name = "decorator" version = "5.0.9" description = "Decorators for Humans" -category = "dev" optional = false python-versions = ">=3.5" +files = [ + {file = "decorator-5.0.9-py3-none-any.whl", hash = "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323"}, + {file = "decorator-5.0.9.tar.gz", hash = "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"}, +] [[package]] name = "distlib" version = "0.3.2" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"}, + {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"}, +] [[package]] name = "django" version = "3.2.12" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "Django-3.2.12-py3-none-any.whl", hash = "sha256:9b06c289f9ba3a8abea16c9c9505f25107809fb933676f6c891ded270039d965"}, + {file = "Django-3.2.12.tar.gz", hash = "sha256:9772e6935703e59e993960832d66a614cf0233a1c5123bc6224ecc6ad69e41e2"}, +] [package.dependencies] asgiref = ">=3.3.2,<4" @@ -302,72 +426,75 @@ bcrypt = ["bcrypt"] name = "django-environ" version = "0.8.1" description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." -category = "main" optional = true python-versions = ">=3.4,<4" +files = [ + {file = "django-environ-0.8.1.tar.gz", hash = "sha256:6f0bc902b43891656b20486938cba0861dc62892784a44919170719572a534cb"}, + {file = "django_environ-0.8.1-py2.py3-none-any.whl", hash = "sha256:42593bee519a527602a467c7b682aee1a051c2597f98c45f4f4f44169ecdb6e5"}, +] [package.extras] -develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] -docs = ["furo (>=2021.8.17b43,<2021.9.0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] [[package]] name = "docutils" version = "0.17.1" description = "Docutils -- Python Documentation Utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, +] [[package]] name = "faker" -version = "6.6.3" +version = "14.2.1" description = "Faker is a Python package that generates fake data for you." -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "Faker-14.2.1-py3-none-any.whl", hash = "sha256:2e28aaea60456857d4ce95dd12aed767769537ad23d13d51a545cd40a654e9d9"}, + {file = "Faker-14.2.1.tar.gz", hash = "sha256:daad7badb4fd916bd047b28c8459ef4689e4fe6acf61f6dfebee8cc602e4d009"}, +] [package.dependencies] python-dateutil = ">=2.4" -text-unidecode = "1.3" +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [[package]] name = "filelock" version = "3.0.12" description = "A platform independent file lock." -category = "dev" optional = false python-versions = "*" - -[[package]] -name = "flake8" -version = "3.9.2" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" +files = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] [[package]] name = "future" version = "0.18.2" description = "Clean single-source support for Python 3 and 2" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +] [[package]] name = "google-auth" version = "2.12.0" description = "Google Authentication Library" -category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" +files = [ + {file = "google-auth-2.12.0.tar.gz", hash = "sha256:f12d86502ce0f2c0174e2e70ecc8d36c69593817e67e1d9c5e34489120422e4b"}, + {file = "google_auth-2.12.0-py2.py3-none-any.whl", hash = "sha256:98f601773978c969e1769f97265e732a81a8e598da3263895023958d456ee625"}, +] [package.dependencies] cachetools = ">=2.0.0,<6.0" @@ -377,7 +504,7 @@ six = ">=1.9.0" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"] -enterprise_cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] pyopenssl = ["pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] @@ -385,9 +512,12 @@ reauth = ["pyu2f (>=0.1.5)"] name = "identify" version = "2.2.11" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.6.1" +files = [ + {file = "identify-2.2.11-py2.py3-none-any.whl", hash = "sha256:7abaecbb414e385752e8ce02d8c494f4fbc780c975074b46172598a28f1ab839"}, + {file = "identify-2.2.11.tar.gz", hash = "sha256:a0e700637abcbd1caae58e0463861250095dfe330a8371733a471af706a4a29a"}, +] [package.extras] license = ["editdistance-s"] @@ -396,17 +526,23 @@ license = ["editdistance-s"] name = "idna" version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] [[package]] name = "importlib-metadata" version = "4.6.1" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"}, + {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"}, +] [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} @@ -421,9 +557,12 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", name = "importlib-resources" version = "5.2.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "importlib_resources-5.2.0-py3-none-any.whl", hash = "sha256:a0143290bef3cbc99de9e40176e4987780939a955b8632f02ce6c935f42e9bfc"}, + {file = "importlib_resources-5.2.0.tar.gz", hash = "sha256:22a2c42d8c6a1d30aa8a0e1f57293725bfd5c013d562585e46aff469e0ff78b3"}, +] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} @@ -436,17 +575,23 @@ testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4) name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] [[package]] name = "ipython" version = "7.16.1" description = "IPython: Productive Interactive Computing" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"}, + {file = "ipython-7.16.1.tar.gz", hash = "sha256:9f4fcb31d3b2c533333893b9172264e4821c1ac91839500f31bd43f2c59b3ccf"}, +] [package.dependencies] appnope = {version = "*", markers = "sys_platform == \"darwin\""} @@ -458,6 +603,7 @@ pexpect = {version = "*", markers = "sys_platform != \"win32\""} pickleshare = "*" prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" pygments = "*" +setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] @@ -475,31 +621,23 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.14)", "pygments" name = "ipython-genutils" version = "0.2.0" description = "Vestigial utilities from IPython" -category = "dev" optional = false python-versions = "*" - -[[package]] -name = "isort" -version = "5.9.2" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] +files = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] [[package]] name = "jedi" version = "0.17.2" description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"}, + {file = "jedi-0.17.2.tar.gz", hash = "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20"}, +] [package.dependencies] parso = ">=0.7.0,<0.8.0" @@ -512,21 +650,27 @@ testing = ["Django (<3.1)", "colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] name = "jeepney" version = "0.7.0" description = "Low-level, pure Python DBus protocol wrapper." -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "jeepney-0.7.0-py3-none-any.whl", hash = "sha256:71335e7a4e93817982f473f3507bffc2eff7a544119ab9b73e089c8ba1409ba3"}, + {file = "jeepney-0.7.0.tar.gz", hash = "sha256:1237cd64c8f7ac3aa4b3f332c4d0fb4a8216f39eaa662ec904302d4d77de5a54"}, +] [package.extras] test = ["pytest", "pytest-asyncio", "pytest-trio", "testpath", "trio"] -trio = ["async-generator", "trio"] +trio = ["async_generator", "trio"] [[package]] name = "keyring" version = "23.0.1" description = "Store and access your passwords safely." -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "keyring-23.0.1-py3-none-any.whl", hash = "sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48"}, + {file = "keyring-23.0.1.tar.gz", hash = "sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8"}, +] [package.dependencies] importlib-metadata = ">=3.6" @@ -542,9 +686,12 @@ testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4) name = "kubernetes" version = "24.2.0" description = "Kubernetes python client" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "kubernetes-24.2.0-py2.py3-none-any.whl", hash = "sha256:da19d58865cf903a8c7b9c3691a2e6315d583a98f0659964656dfdf645bf7e49"}, + {file = "kubernetes-24.2.0.tar.gz", hash = "sha256:9900f12ae92007533247167d14cdee949cd8c7721f88b4a7da5f5351da3834cd"}, +] [package.dependencies] certifi = ">=14.05.14" @@ -553,9 +700,10 @@ python-dateutil = ">=2.5.3" pyyaml = ">=5.4.1" requests = "*" requests-oauthlib = "*" +setuptools = ">=21.0.0" six = ">=1.9.0" urllib3 = ">=1.24.2" -websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.0 || >=0.43.0" +websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0" [package.extras] adal = ["adal (>=1.0.2)"] @@ -564,69 +712,102 @@ adal = ["adal (>=1.0.2)"] name = "m2r" version = "0.2.1" description = "Markdown and reStructuredText in a single file." -category = "dev" optional = false python-versions = "*" +files = [ + {file = "m2r-0.2.1.tar.gz", hash = "sha256:bf90bad66cda1164b17e5ba4a037806d2443f2a4d5ddc9f6a5554a0322aaed99"}, +] [package.dependencies] docutils = "*" mistune = "*" -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "mistune" version = "0.8.4" description = "The fastest markdown parser in pure Python" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"}, + {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, +] [[package]] name = "mypy" -version = "0.812" +version = "0.971" description = "Optional static typing for Python" -category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" +files = [ + {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"}, + {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"}, + {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"}, + {file = "mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"}, + {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"}, + {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"}, + {file = "mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"}, + {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"}, + {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"}, + {file = "mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"}, + {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"}, + {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"}, + {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"}, + {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"}, + {file = "mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"}, + {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"}, + {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"}, + {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"}, + {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"}, + {file = "mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"}, + {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"}, + {file = "mypy-0.971-py3-none-any.whl", hash = "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"}, + {file = "mypy-0.971.tar.gz", hash = "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"}, +] [package.dependencies] -mypy-extensions = ">=0.4.3,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" -typing-extensions = ">=3.7.4" +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} +typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] [[package]] name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" optional = false python-versions = "*" +files = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] [[package]] name = "nodeenv" version = "1.6.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, +] [[package]] name = "oauthlib" version = "3.2.1" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "oauthlib-3.2.1-py3-none-any.whl", hash = "sha256:88e912ca1ad915e1dcc1c06fc9259d19de8deacd6fd17cc2df266decc2e49066"}, + {file = "oauthlib-3.2.1.tar.gz", hash = "sha256:1565237372795bf6ee3e5aba5e2a85bd5a65d0e2aa5c628b9a97b7d7a0da3721"}, +] [package.extras] rsa = ["cryptography (>=3.0.0)"] @@ -637,9 +818,12 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] name = "packaging" version = "21.0" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] [package.dependencies] pyparsing = ">=2.0.2" @@ -648,28 +832,26 @@ pyparsing = ">=2.0.2" name = "parso" version = "0.7.1" description = "A Python Parser" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "parso-0.7.1-py2.py3-none-any.whl", hash = "sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea"}, + {file = "parso-0.7.1.tar.gz", hash = "sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"}, +] [package.extras] testing = ["docopt", "pytest (>=3.0.7)"] -[[package]] -name = "pathspec" -version = "0.8.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] [package.dependencies] ptyprocess = ">=0.5" @@ -678,17 +860,23 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] [[package]] name = "pkginfo" version = "1.7.1" description = "Query metadatdata from sdists / bdists / installed packages." -category = "dev" optional = false python-versions = "*" +files = [ + {file = "pkginfo-1.7.1-py2.py3-none-any.whl", hash = "sha256:37ecd857b47e5f55949c41ed061eb51a0bee97a87c969219d144c0e023982779"}, + {file = "pkginfo-1.7.1.tar.gz", hash = "sha256:e7432f81d08adec7297633191bbf0bd47faf13cd8724c3a13250e51d542635bd"}, +] [package.extras] testing = ["coverage", "nose"] @@ -697,17 +885,23 @@ testing = ["coverage", "nose"] name = "platformdirs" version = "2.0.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "platformdirs-2.0.2-py2.py3-none-any.whl", hash = "sha256:0b9547541f599d3d242078ae60b927b3e453f0ad52f58b4d4bc3be86aed3ec41"}, + {file = "platformdirs-2.0.2.tar.gz", hash = "sha256:3b00d081227d9037bbbca521a5787796b5ef5000faea1e43fd76f1d44b06fcfa"}, +] [[package]] name = "pluggy" version = "0.13.1" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] [package.dependencies] importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} @@ -717,17 +911,20 @@ dev = ["pre-commit", "tox"] [[package]] name = "pre-commit" -version = "2.13.0" +version = "2.17.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.6.1" +files = [ + {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"}, + {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"}, +] [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -importlib-resources = {version = "*", markers = "python_version < \"3.7\""} +importlib-resources = {version = "<5.3", markers = "python_version < \"3.7\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" toml = "*" @@ -737,9 +934,12 @@ virtualenv = ">=20.0.8" name = "prompt-toolkit" version = "3.0.19" description = "Library for building powerful interactive command lines in Python" -category = "dev" optional = false python-versions = ">=3.6.1" +files = [ + {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"}, + {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"}, +] [package.dependencies] wcwidth = "*" @@ -748,76 +948,81 @@ wcwidth = "*" name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] [[package]] name = "py" version = "1.10.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] [[package]] name = "pyasn1" version = "0.4.8" description = "ASN.1 types and codecs" -category = "main" optional = false python-versions = "*" +files = [ + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] [[package]] name = "pyasn1-modules" version = "0.2.8" description = "A collection of ASN.1-based protocols modules." -category = "main" optional = false python-versions = "*" +files = [ + {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, + {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, +] [package.dependencies] pyasn1 = ">=0.4.6,<0.5.0" -[[package]] -name = "pycodestyle" -version = "2.7.0" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - [[package]] name = "pycparser" version = "2.20" description = "C parser in Python" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "pyflakes" -version = "2.3.1" -description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, +] [[package]] name = "pygments" version = "2.9.0" description = "Pygments is a syntax highlighting package written in Python." -category = "dev" optional = false python-versions = ">=3.5" +files = [ + {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, + {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, +] [[package]] name = "pyjwt" version = "2.1.0" description = "JSON Web Token implementation in Python" -category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "PyJWT-2.1.0-py3-none-any.whl", hash = "sha256:934d73fbba91b0483d3857d1aff50e96b2a892384ee2c17417ed3203f173fca1"}, + {file = "PyJWT-2.1.0.tar.gz", hash = "sha256:fba44e7898bbca160a2b2b501f492824fc8382485d3a6f11ba5d0c1937ce6130"}, +] [package.extras] crypto = ["cryptography (>=3.3.1,<4.0.0)"] @@ -829,9 +1034,12 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] name = "pymysql" version = "1.0.2" description = "Pure Python MySQL Driver" -category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "PyMySQL-1.0.2-py3-none-any.whl", hash = "sha256:41fc3a0c5013d5f039639442321185532e3e2c8924687abe6537de157d403641"}, + {file = "PyMySQL-1.0.2.tar.gz", hash = "sha256:816927a350f38d56072aeca5dfb10221fe1dc653745853d30a216637f5d7ad36"}, +] [package.extras] ed25519 = ["PyNaCl (>=1.4.0)"] @@ -841,17 +1049,23 @@ rsa = ["cryptography"] name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] [[package]] name = "pytest" -version = "6.2.4" +version = "7.0.1" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, + {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, +] [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} @@ -860,51 +1074,59 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<1.0.0a1" +pluggy = ">=0.12,<2.0" py = ">=1.8.2" -toml = "*" +tomli = ">=1.0.0" [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-cov" -version = "2.12.1" +version = "4.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] [package.dependencies] -coverage = ">=5.2.1" +coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" -toml = "*" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pytest-django" -version = "4.4.0" +version = "4.5.2" description = "A Django plugin for pytest." -category = "dev" optional = false python-versions = ">=3.5" +files = [ + {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, + {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, +] [package.dependencies] pytest = ">=5.4.0" [package.extras] docs = ["sphinx", "sphinx-rtd-theme"] -testing = ["django", "django-configurations (>=2.0)"] +testing = ["Django", "django-configurations (>=2.0)"] [[package]] name = "pytest-mock" version = "3.6.1" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, + {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, +] [package.dependencies] pytest = ">=5.0" @@ -912,13 +1134,31 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "pytest-pretty" +version = "1.2.0" +description = "pytest plugin for printing summary data as I want it" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_pretty-1.2.0-py3-none-any.whl", hash = "sha256:6f79122bf53864ae2951b6c9e94d7a06a87ef753476acd4588aeac018f062036"}, + {file = "pytest_pretty-1.2.0.tar.gz", hash = "sha256:105a355f128e392860ad2c478ae173ff96d2f03044692f9818ff3d49205d3a60"}, +] + +[package.dependencies] +pytest = ">=7" +rich = ">=12" + [[package]] name = "python-dateutil" version = "2.8.1" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] [package.dependencies] six = ">=1.5" @@ -927,33 +1167,72 @@ six = ">=1.5" name = "pytz" version = "2021.3" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" +files = [ + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, +] [[package]] name = "pywin32-ctypes" version = "0.2.0" description = "" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, + {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, +] [[package]] name = "pyyaml" version = "5.4.1" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] [[package]] name = "readme-renderer" version = "29.0" description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "readme_renderer-29.0-py2.py3-none-any.whl", hash = "sha256:63b4075c6698fcfa78e584930f07f39e05d46f3ec97f65006e430b595ca6348c"}, + {file = "readme_renderer-29.0.tar.gz", hash = "sha256:92fd5ac2bf8677f310f3303aa4bce5b9d5f9f2094ab98c29f13791d7b805a3db"}, +] [package.dependencies] bleach = ">=2.1.0" @@ -964,23 +1243,18 @@ six = "*" [package.extras] md = ["cmarkgfm (>=0.5.0,<0.6.0)"] -[[package]] -name = "regex" -version = "2021.7.6" -description = "Alternative regular expression module, to replace re." -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "requests" version = "2.26.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.dependencies] +files = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] + +[package.dependencies] certifi = ">=2017.4.17" charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} @@ -988,15 +1262,18 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "requests-oauthlib" version = "1.3.1" description = "OAuthlib authentication support for Requests." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, + {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, +] [package.dependencies] oauthlib = ">=3.0.0" @@ -1009,9 +1286,12 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] name = "requests-toolbelt" version = "0.9.1" description = "A utility belt for advanced users of python-requests" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"}, + {file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"}, +] [package.dependencies] requests = ">=2.0.1,<3.0.0" @@ -1020,75 +1300,159 @@ requests = ">=2.0.1,<3.0.0" name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] [package.extras] idna2008 = ["idna"] +[[package]] +name = "rich" +version = "12.0.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.6.2,<4.0.0" +files = [ + {file = "rich-12.0.1-py3-none-any.whl", hash = "sha256:ce5c714e984a2d185399e4e1dd1f8b2feacb7cecfc576f1522425643a36a57ea"}, + {file = "rich-12.0.1.tar.gz", hash = "sha256:3fba9dd15ebe048e2795a02ac19baee79dc12cc50b074ef70f2958cd651b59a9"}, +] + +[package.dependencies] +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" +typing-extensions = {version = ">=3.7.4,<5.0", markers = "python_version < \"3.8\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] + [[package]] name = "rsa" version = "4.9" description = "Pure-Python RSA implementation" -category = "main" optional = false python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] [package.dependencies] pyasn1 = ">=0.1.3" +[[package]] +name = "ruff" +version = "0.1.6" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"}, + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"}, + {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"}, + {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"}, + {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"}, + {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"}, +] + [[package]] name = "secretstorage" version = "3.3.1" description = "Python bindings to FreeDesktop.org Secret Service API" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, + {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, +] [package.dependencies] cryptography = ">=2.0" jeepney = ">=0.6" +[[package]] +name = "setuptools" +version = "59.6.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.6" +files = [ + {file = "setuptools-59.6.0-py3-none-any.whl", hash = "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"}, + {file = "setuptools-59.6.0.tar.gz", hash = "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=8.2)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-inline-tabs", "sphinxcontrib-towncrier"] +testing = ["flake8-2020", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "paver", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy", "pytest-virtualenv (>=1.2.7)", "pytest-xdist", "sphinx", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] [[package]] name = "sqlparse" version = "0.4.2" description = "A non-validating SQL parser." -category = "main" optional = false python-versions = ">=3.5" - -[[package]] -name = "text-unidecode" -version = "1.3" -description = "The most basic Text::Unidecode port" -category = "dev" -optional = false -python-versions = "*" +files = [ + {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, + {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, +] [[package]] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "1.2.3" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, + {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, +] [[package]] name = "tox" version = "3.23.1" description = "tox is a generic virtualenv management and test command line tool" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "tox-3.23.1-py2.py3-none-any.whl", hash = "sha256:b0b5818049a1c1997599d42012a637a33f24c62ab8187223fdd318fa8522637b"}, + {file = "tox-3.23.1.tar.gz", hash = "sha256:307a81ddb82bd463971a273f33e9533a24ed22185f27db8ce3386bff27d324e3"}, +] [package.dependencies] colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} @@ -1109,9 +1473,12 @@ testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psu name = "tqdm" version = "4.61.2" description = "Fast, Extensible Progress Meter" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "tqdm-4.61.2-py2.py3-none-any.whl", hash = "sha256:5aa445ea0ad8b16d82b15ab342de6b195a722d75fc1ef9934a46bba6feafbc64"}, + {file = "tqdm-4.61.2.tar.gz", hash = "sha256:8bb94db0d4468fea27d004a0f1d1c02da3cdedc00fe491c0de986b76a04d6b0a"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -1125,9 +1492,12 @@ telegram = ["requests"] name = "traitlets" version = "4.3.3" description = "Traitlets Python config system" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, + {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, +] [package.dependencies] decorator = "*" @@ -1141,9 +1511,12 @@ test = ["mock", "pytest"] name = "twine" version = "3.4.1" description = "Collection of utilities for publishing packages on PyPI" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "twine-3.4.1-py3-none-any.whl", hash = "sha256:16f706f2f1687d7ce30e7effceee40ed0a09b7c33b9abb5ef6434e5551565d83"}, + {file = "twine-3.4.1.tar.gz", hash = "sha256:a56c985264b991dc8a8f4234eb80c5af87fa8080d0c224ad8f2cd05a2c22e83b"}, +] [package.dependencies] colorama = ">=0.4.3" @@ -1160,25 +1533,85 @@ tqdm = ">=4.14" name = "typed-ast" version = "1.4.3" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, +] + +[[package]] +name = "types-pymysql" +version = "1.1.0.1" +description = "Typing stubs for PyMySQL" +optional = false +python-versions = "*" +files = [ + {file = "types-PyMySQL-1.1.0.1.tar.gz", hash = "sha256:72bdaecb88de4a30bc3e1842e1d4522ceb3c4b2e883a6a2a7a7162775dd27b93"}, + {file = "types_PyMySQL-1.1.0.1-py3-none-any.whl", hash = "sha256:9aec9ee0453314d477ef26e5832b4a992bc4cc3557358d62b0fe4af760a7728f"}, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.9" +description = "Typing stubs for PyYAML" +optional = false +python-versions = "*" +files = [ + {file = "types-PyYAML-6.0.12.9.tar.gz", hash = "sha256:c51b1bd6d99ddf0aa2884a7a328810ebf70a4262c292195d3f4f9a0005f9eeb6"}, + {file = "types_PyYAML-6.0.12.9-py3-none-any.whl", hash = "sha256:5aed5aa66bd2d2e158f75dda22b059570ede988559f030cf294871d3b647e3e8"}, +] [[package]] name = "typing-extensions" version = "3.10.0.0" description = "Backported and Experimental Type Hints for Python 3.5+" -category = "main" optional = false python-versions = "*" +files = [ + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, +] [[package]] name = "urllib3" version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +files = [ + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, +] [package.extras] brotli = ["brotlipy (>=0.6.0)"] @@ -1189,9 +1622,12 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "virtualenv" version = "20.5.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "virtualenv-20.5.0-py2.py3-none-any.whl", hash = "sha256:b7afa7f32abbf7dd4c24269a596cfbb0a422bb83c47215a785a7bf607cb88e1b"}, + {file = "virtualenv-20.5.0.tar.gz", hash = "sha256:6b0e3eeb6cb081c9c81ec85633785e29edcdf6ff271d70e0d1e2bd616495c08c"}, +] [package.dependencies] "backports.entry-points-selectable" = ">=1.0.4" @@ -1210,25 +1646,34 @@ testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", name = "wcwidth" version = "0.2.5" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] [[package]] name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] [[package]] name = "websocket-client" version = "1.3.1" description = "WebSocket client for Python with low level API options" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "websocket-client-1.3.1.tar.gz", hash = "sha256:6278a75065395418283f887de7c3beafb3aa68dada5cacbe4b214e8d26da499b"}, + {file = "websocket_client-1.3.1-py3-none-any.whl", hash = "sha256:074e2ed575e7c822fc0940d31c3ac9bb2b1142c303eafcf3e304e6ce035522e8"}, +] [package.extras] docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] @@ -1239,9 +1684,12 @@ test = ["websockets"] name = "zipp" version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, +] [package.extras] docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] @@ -1249,367 +1697,11 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black ( [extras] cryptography = ["cryptography", "pyjwt"] -demo = ["django-environ", "Django", "PyMySQL", "pyjwt"] +demo = ["Django", "PyMySQL", "django-environ", "pyjwt"] django = ["Django", "pyjwt"] kubernetes = ["kubernetes"] [metadata] -lock-version = "1.1" +lock-version = "2.0" python-versions = "^3.6.1" -content-hash = "610465f5963e1c1cf117977a26dd1dfa195a4460f4c421efbd3415045eb99085" - -[metadata.files] -appdirs = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] -appnope = [ - {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, - {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, -] -asgiref = [] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, -] -autoflake = [] -backcall = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] -"backports.entry-points-selectable" = [ - {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, - {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, -] -bkapi-bk-apigateway = [ - {file = "bkapi-bk-apigateway-1.0.11.tar.gz", hash = "sha256:fcdbc4eca8bfd3310995cec532ae127ee0533ea858c82916d9782e4df3df4c49"}, -] -bkapi-client-core = [] -black = [ - {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, -] -bleach = [] -cachetools = [] -certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, -] -cffi = [] -cfgv = [ - {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"}, - {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"}, -] -charset-normalizer = [] -click = [] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -coverage = [] -cryptography = [] -curlify = [] -dataclasses = [] -decorator = [ - {file = "decorator-5.0.9-py3-none-any.whl", hash = "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323"}, - {file = "decorator-5.0.9.tar.gz", hash = "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"}, -] -distlib = [ - {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"}, - {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"}, -] -django = [] -django-environ = [] -docutils = [] -faker = [] -filelock = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, -] -flake8 = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, -] -future = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, -] -google-auth = [] -identify = [ - {file = "identify-2.2.11-py2.py3-none-any.whl", hash = "sha256:7abaecbb414e385752e8ce02d8c494f4fbc780c975074b46172598a28f1ab839"}, - {file = "identify-2.2.11.tar.gz", hash = "sha256:a0e700637abcbd1caae58e0463861250095dfe330a8371733a471af706a4a29a"}, -] -idna = [] -importlib-metadata = [ - {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"}, - {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"}, -] -importlib-resources = [ - {file = "importlib_resources-5.2.0-py3-none-any.whl", hash = "sha256:a0143290bef3cbc99de9e40176e4987780939a955b8632f02ce6c935f42e9bfc"}, - {file = "importlib_resources-5.2.0.tar.gz", hash = "sha256:22a2c42d8c6a1d30aa8a0e1f57293725bfd5c013d562585e46aff469e0ff78b3"}, -] -iniconfig = [] -ipython = [ - {file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"}, - {file = "ipython-7.16.1.tar.gz", hash = "sha256:9f4fcb31d3b2c533333893b9172264e4821c1ac91839500f31bd43f2c59b3ccf"}, -] -ipython-genutils = [ - {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, - {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, -] -isort = [ - {file = "isort-5.9.2-py3-none-any.whl", hash = "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813"}, - {file = "isort-5.9.2.tar.gz", hash = "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"}, -] -jedi = [] -jeepney = [] -keyring = [] -kubernetes = [] -m2r = [] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -mistune = [] -mypy = [ - {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, - {file = "mypy-0.812-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c"}, - {file = "mypy-0.812-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521"}, - {file = "mypy-0.812-cp35-cp35m-win_amd64.whl", hash = "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"}, - {file = "mypy-0.812-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a"}, - {file = "mypy-0.812-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c"}, - {file = "mypy-0.812-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6"}, - {file = "mypy-0.812-cp36-cp36m-win_amd64.whl", hash = "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064"}, - {file = "mypy-0.812-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56"}, - {file = "mypy-0.812-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8"}, - {file = "mypy-0.812-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7"}, - {file = "mypy-0.812-cp37-cp37m-win_amd64.whl", hash = "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564"}, - {file = "mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506"}, - {file = "mypy-0.812-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5"}, - {file = "mypy-0.812-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66"}, - {file = "mypy-0.812-cp38-cp38-win_amd64.whl", hash = "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e"}, - {file = "mypy-0.812-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a"}, - {file = "mypy-0.812-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a"}, - {file = "mypy-0.812-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97"}, - {file = "mypy-0.812-cp39-cp39-win_amd64.whl", hash = "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df"}, - {file = "mypy-0.812-py3-none-any.whl", hash = "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4"}, - {file = "mypy-0.812.tar.gz", hash = "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -nodeenv = [ - {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, - {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, -] -oauthlib = [] -packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, -] -parso = [] -pathspec = [ - {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, - {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, -] -pexpect = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, -] -pickleshare = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] -pkginfo = [] -platformdirs = [ - {file = "platformdirs-2.0.2-py2.py3-none-any.whl", hash = "sha256:0b9547541f599d3d242078ae60b927b3e453f0ad52f58b4d4bc3be86aed3ec41"}, - {file = "platformdirs-2.0.2.tar.gz", hash = "sha256:3b00d081227d9037bbbca521a5787796b5ef5000faea1e43fd76f1d44b06fcfa"}, -] -pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, -] -pre-commit = [ - {file = "pre_commit-2.13.0-py2.py3-none-any.whl", hash = "sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4"}, - {file = "pre_commit-2.13.0.tar.gz", hash = "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378"}, -] -prompt-toolkit = [] -ptyprocess = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] -py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, -] -pyasn1 = [ - {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, - {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, - {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, - {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, - {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, - {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, - {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, - {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, - {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, - {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, - {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, - {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, -] -pyasn1-modules = [] -pycodestyle = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, -] -pycparser = [ - {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, - {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, -] -pyflakes = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, -] -pygments = [] -pyjwt = [] -pymysql = [] -pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, -] -pytest = [] -pytest-cov = [] -pytest-django = [] -pytest-mock = [ - {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, - {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, - {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, -] -pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, -] -pywin32-ctypes = [] -pyyaml = [ - {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, - {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, - {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, - {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, - {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, - {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, - {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, - {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, - {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, - {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, - {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, - {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, - {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, - {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, - {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, - {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, - {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, -] -readme-renderer = [] -regex = [] -requests = [ - {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, - {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, -] -requests-oauthlib = [] -requests-toolbelt = [] -rfc3986 = [] -rsa = [] -secretstorage = [] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -sqlparse = [ - {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, - {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, -] -text-unidecode = [ - {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, - {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tox = [ - {file = "tox-3.23.1-py2.py3-none-any.whl", hash = "sha256:b0b5818049a1c1997599d42012a637a33f24c62ab8187223fdd318fa8522637b"}, - {file = "tox-3.23.1.tar.gz", hash = "sha256:307a81ddb82bd463971a273f33e9533a24ed22185f27db8ce3386bff27d324e3"}, -] -tqdm = [] -traitlets = [ - {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, - {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, -] -twine = [] -typed-ast = [ - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, - {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, - {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, - {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, - {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, - {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, - {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, - {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, - {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, - {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, -] -typing-extensions = [ - {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, - {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, - {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, -] -urllib3 = [] -virtualenv = [] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] -webencodings = [] -websocket-client = [] -zipp = [ - {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, - {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, -] +content-hash = "a3b159e317addca68ab16f47c91a784dd5b60dc263df85f4b6dfd17fdcfa7172" diff --git a/sdks/apigw-manager/pyproject.toml b/sdks/apigw-manager/pyproject.toml index 21956fe6..db7efd0c 100644 --- a/sdks/apigw-manager/pyproject.toml +++ b/sdks/apigw-manager/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "apigw-manager" -version = "2.0.2" +version = "3.0.0" description = "The SDK for managing blueking gateway resource." readme = "README.md" authors = ["blueking "] @@ -20,8 +20,8 @@ setuptools = ">=21.0.0" urllib3 = ">=1.25.3" future = "0.18.2" pyyaml = ">=5.4.1" +bkapi-client-core = ">=1.2.0" bkapi-bk-apigateway = "^1.0.11" -bkapi-client-core = ">=1.1.3" pyjwt = {version = ">=1.6.4", optional = true} django-environ = {version = ">=0.8.1", optional = true} Django = {version = ">=1.11.1", optional = true} @@ -37,30 +37,135 @@ demo = ["django-environ", "django", "PyMySQL", "pyjwt"] kubernetes = ["kubernetes"] [tool.poetry.dev-dependencies] +pytest = "^7.0.1" +pytest-cov = "^4.0.0" +pytest-mock = "^3.6.1" +pytest-django = "^4.5.0" +pytest-pretty = {version = "^1.1.0", python = "~3.7.0"} +Faker = "14.2.1" +ruff = {version = "^0.1.3", python = "~3.7.0"} +mypy = "*" +pre-commit = "^2.17.0" m2r = "^0.2.1" -pytest = "^6.2.2" -pytest-cov = ">=2.8.1" -black = "^20.8b1" -isort = "^5.8.0" -autoflake = "^1.4" -pre-commit = "^2.11.1" -mypy = "^0.812" -flake8 = "^3.9.0" -python-dateutil = "2.8.1,<3.0.0" -Faker = "^6.6.3" -pytest-mock = "^3.5.1" tox = "^3.23.0" -ipython = "7.16.1" -jedi = "0.17.2" -pytest-django = "^4.1.0" -python_dateutil = ">=2.5.3" +ipython = "^7" twine = "^3.4.1" django = ">=1.11.1" kubernetes = "^24.2.0" +types-PyYAML = "6.0.12.9" +types-PyMySQL = "1.1.0.1" -[tool.black] +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.mypy] +ignore_missing_imports = true +follow_imports = "skip" +no_implicit_optional = true +show_error_codes = true +strict_optional = true +pretty = true + +[[tool.mypy.overrides]] +module = [ + "*.migrations.*", +] +ignore_errors = true + +[tool.pytest.ini_options] +addopts = "-p no:pastebin -p no:nose -p no:doctest -p no:warnings" +testpaths = ["tests"] + +[tool.ruff] +# https://docs.astral.sh/ruff/rules/ +select = [ + "E", + "F", + "W", + "I", + "C90", + "B", + "PIE", + "C4", + "PL", + "RET", + "N", + "PERF", + "G", + "TRY", + "SIM", + "PT", +] + +# Disable E501 until this issue is fixed: https://github.com/astral-sh/ruff/issues/3825 +ignore = [ + # https://beta.ruff.rs/docs/rules/assert-raises-exception/ + "B017", + # https://beta.ruff.rs/docs/rules/raise-without-from-inside-except/ + "B904", + # https://beta.ruff.rs/docs/rules/zip-without-explicit-strict/ + "B905", + # https://beta.ruff.rs/docs/rules/line-too-long/ + "E501", + # https://beta.ruff.rs/docs/rules/ambiguous-variable-name/ + "E741", + # https://beta.ruff.rs/docs/rules/unused-variable/ + "F841", + # https://beta.ruff.rs/docs/rules/error-suffix-on-exception-name/ + "N818", + # https://beta.ruff.rs/docs/rules/try-except-in-loop/ + "PERF203", + # https://beta.ruff.rs/docs/rules/too-many-arguments/ + "PLR0913", + # https://beta.ruff.rs/docs/rules/raise-vanilla-args/ + "TRY003", + # https://beta.ruff.rs/docs/rules/reraise-no-cause/ + "TRY200", + # https://beta.ruff.rs/docs/rules/try-consider-else/ + "TRY300", + # https://beta.ruff.rs/docs/rules/raise-within-try/ + "TRY301", + # https://beta.ruff.rs/docs/rules/magic-value-comparison/ + "PLR2004", + # https://beta.ruff.rs/docs/rules/suppressible-exception/ + "SIM105", + # https://beta.ruff.rs/docs/rules/open-file-with-context-handler/ + "SIM115", +] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + "*/migrations/*", +] + +# Same as Black. line-length = 119 -[build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 12 + +[tool.ruff.isort] +relative-imports-order = "closest-to-furthest" +known-first-party = ["apigw_manager"] \ No newline at end of file diff --git a/sdks/apigw-manager/requirements_tox.txt b/sdks/apigw-manager/requirements_tox.txt new file mode 100644 index 00000000..0f686a7a --- /dev/null +++ b/sdks/apigw-manager/requirements_tox.txt @@ -0,0 +1,100 @@ +appnope==0.1.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform == "darwin" +asgiref==3.4.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +atomicwrites==1.4.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform == "win32" +attrs==21.2.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +backcall==0.2.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +backports-entry-points-selectable==1.1.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +bkapi-bk-apigateway==1.0.11 ; python_full_version >= "3.6.1" and python_version < "4.0" +bkapi-client-core==1.2.0 ; python_full_version >= "3.6.1" and python_version < "4.0" +bleach==3.3.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +cachetools==4.2.4 ; python_full_version >= "3.6.1" and python_version < "4.0" +certifi==2021.5.30 ; python_full_version >= "3.6.1" and python_version < "4.0" +cffi==1.14.6 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +cfgv==3.3.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +charset-normalizer==2.0.1 ; python_full_version >= "3.6.1" and python_version < "4.0" +colorama==0.4.4 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +commonmark==0.9.1 ; python_version >= "3.7" and python_full_version < "3.8.0" +coverage[toml]==5.5 ; python_full_version >= "3.6.1" and python_version < "4" +cryptography==3.4.7 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +curlify==2.2.1 ; python_full_version >= "3.6.1" and python_version < "4.0" +decorator==5.0.9 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +distlib==0.3.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +django-environ==0.8.1 ; python_full_version >= "3.6.1" and python_version < "4" +django==3.2.12 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +docutils==0.17.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +faker==14.2.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +filelock==3.0.12 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +future==0.18.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +google-auth==2.12.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +identify==2.2.11 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +idna==3.2 ; python_full_version >= "3.6.1" and python_version < "4.0" +importlib-metadata==4.6.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +importlib-resources==5.2.0 ; python_full_version >= "3.6.1" and python_version < "3.7" +iniconfig==1.1.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +ipython-genutils==0.2.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +ipython==7.16.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +jedi==0.17.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +jeepney==0.7.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform == "linux" +keyring==23.0.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +kubernetes==24.2.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +m2r==0.2.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +mistune==0.8.4 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +mypy-extensions==0.4.3 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +mypy==0.971 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +nodeenv==1.6.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +oauthlib==3.2.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +packaging==21.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +parso==0.7.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pexpect==4.8.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform != "win32" +pickleshare==0.7.5 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pkginfo==1.7.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +platformdirs==2.0.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pluggy==0.13.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pre-commit==2.17.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +prompt-toolkit==3.0.19 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +ptyprocess==0.7.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform != "win32" +py==1.10.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pyasn1-modules==0.2.8 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pyasn1==0.4.8 ; python_full_version >= "3.6.1" and python_version < "4" +pycparser==2.20 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pygments==2.9.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pyjwt==2.1.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pymysql==1.0.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pyparsing==2.4.7 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pytest-cov==4.0.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pytest-django==4.5.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pytest-mock==3.6.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pytest-pretty==1.2.0 ; python_version >= "3.7" and python_full_version < "3.8.0" +pytest==7.0.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +python-dateutil==2.8.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pytz==2021.3 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +pywin32-ctypes==0.2.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform == "win32" +pyyaml==5.4.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +readme-renderer==29.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +requests-oauthlib==1.3.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +requests-toolbelt==0.9.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +requests==2.26.0 ; python_full_version >= "3.6.1" and python_version < "4.0" +rfc3986==1.5.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +rich==12.0.1 ; python_version >= "3.7" and python_full_version < "3.8.0" +rsa==4.9 ; python_full_version >= "3.6.1" and python_version < "4" +ruff==0.1.6 ; python_version >= "3.7" and python_full_version < "3.8.0" +secretstorage==3.3.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and sys_platform == "linux" +setuptools==59.6.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +six==1.16.0 ; python_full_version >= "3.6.1" and python_version < "4.0" +sqlparse==0.4.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +toml==0.10.2 ; python_full_version >= "3.6.1" and python_version < "4" +tomli==1.2.3 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +tox==3.23.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +tqdm==4.61.2 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +traitlets==4.3.3 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +twine==3.4.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +typed-ast==1.4.3 ; python_full_version >= "3.6.1" and python_version < "3.8" +types-pymysql==1.1.0.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +types-pyyaml==6.0.12.9 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +typing-extensions==3.10.0.0 ; python_full_version >= "3.6.1" and python_version < "4.0" +urllib3==1.26.6 ; python_full_version >= "3.6.1" and python_version < "4" +virtualenv==20.5.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +wcwidth==0.2.5 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +webencodings==0.5.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +websocket-client==1.3.1 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" +zipp==3.5.0 ; python_full_version >= "3.6.1" and python_full_version < "4.0.0" diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/authentication.py b/sdks/apigw-manager/src/apigw_manager/apigw/authentication.py index 870c203c..2b72de97 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/authentication.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/authentication.py @@ -61,7 +61,6 @@ def __init__(self, get_response): ) def __call__(self, request): - jwt = self.provider.provide(request) if not jwt: return self.get_response(request) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/command.py b/sdks/apigw-manager/src/apigw_manager/apigw/command.py index 9ca9ab1a..9586cea9 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/command.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/command.py @@ -24,11 +24,10 @@ class ApiCommand(BaseCommand): - manager_class: typing.Callable def add_arguments(self, parser): - parser.add_argument("--api-name", help="api name") + parser.add_argument("--gateway-name", "--api-name", dest="api_name", help="gateway name") parser.add_argument("--host", help="apigateway host with stage of admin api `bk-apigateway`") def get_configuration(self, **kwargs): @@ -39,7 +38,7 @@ def handle(self, *args, **kwargs): manager = self.manager_class(configuration) try: - self.do(manager=manager, configuration=configuration, *args, **kwargs) + self.do(manager, configuration, *args, **kwargs) except ApiResponseError as err: self.stderr.write(str(err)) sys.exit(1) @@ -89,12 +88,12 @@ def handle(self, *args, **kwargs): definition = self.get_definition(**kwargs) try: - self.do(manager=manager, definition=definition, configuration=configuration, *args, **kwargs) + self.do(manager, definition, configuration, *args, **kwargs) except ApiResponseError as err: self.stderr.write(str(err)) sys.exit(1) - def do(self, manager, definition, *args, **kwargs): + def do(self, manager, definition, configuration, *args, **kwargs): pass diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/decorators.py b/sdks/apigw-manager/src/apigw_manager/apigw/decorators.py index 15c9640b..fe08a5e1 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/decorators.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/decorators.py @@ -19,7 +19,6 @@ def apigw_require(view_func): def wrapper(request, *args, **kwargs): - exempt = getattr(settings, "BK_APIGW_REQUIRE_EXEMPT", False) if exempt: return view_func(request, *args, **kwargs) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/helper.py b/sdks/apigw-manager/src/apigw_manager/apigw/helper.py index 65a1b87d..964fe854 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/helper.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/helper.py @@ -52,7 +52,6 @@ def __init__(self, definition): def _check_spec_version(self, definition): spec_version = definition.get("spec_version") if not spec_version: - logger.warning("please add `spec_version: 1` to definition.yaml") return if str(spec_version) not in self.valid_spec_versions: diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/k8s_helper.py b/sdks/apigw-manager/src/apigw_manager/apigw/k8s_helper.py index 3cf43c70..a3cb0a7c 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/k8s_helper.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/k8s_helper.py @@ -9,7 +9,6 @@ class SecretPublicKeyManager(BasePublicKeyManager): def __init__(self): - self.namespace = getattr(settings, "APIGW_JWT_PUBLIC_KEY_SECRET_NAMESPACE", "default") self.secret_mappings = getattr(settings, "APIGW_JWT_PUBLIC_KEY_SECRET_MAPPINGS", {}) @@ -18,7 +17,6 @@ def __init__(self): self.client = CoreV1Api(api_client=api_client.ApiClient(configuration=configuration)) def get(self, api_name, issuer=None): - try: secret = self.client.read_namespaced_secret(self._get_name(issuer), self.namespace) except exceptions.ApiException as err: @@ -37,7 +35,6 @@ def get(self, api_name, issuer=None): return base64.b64decode(value).decode() def set(self, api_name, public_key, issuer=None): - name = self._get_name(issuer) secret = V1Secret( metadata=V1ObjectMeta( diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/add_related_apps.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/add_related_apps.py index f5a1e5d3..75c27aae 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/add_related_apps.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/add_related_apps.py @@ -28,10 +28,4 @@ def do(self, manager, definition, *args, **kwargs): print("warning!! Add related apps error, %s" % str(err)) return - print( - "Add related apps for gateway %s: %s" - % ( - manager.config.api_name, - ", ".join(definition) - ) - ) + print("Add related apps for gateway %s: %s" % (manager.config.api_name, ", ".join(definition))) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/apply_apigw_permissions.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/apply_apigw_permissions.py index f13ad382..d7105be5 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/apply_apigw_permissions.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/apply_apigw_permissions.py @@ -23,14 +23,20 @@ def do(self, manager, definition, *args, **kwargs): for permission in definition: permission.setdefault("target_app_code", manager.config.bk_app_code) - permission.setdefault("grant_dimension", "api") - result = manager.apply_permission(**permission) + if permission.get("gateway_name"): + permission["api_name"] = permission.get("gateway_name") + + grant_dimension = permission.pop("grant_dimension", "api") + if grant_dimension == "gateway": + grant_dimension = "api" + + result = manager.apply_permission(grant_dimension=grant_dimension, **permission) print( - "Applied permissions for API gateway %s, record %s, dimension %s" + "Applied permissions for gateway %s, record %s, dimension %s" % ( permission["api_name"], result["record_id"], - permission["grant_dimension"], + grant_dimension, ) ) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/create_version_and_release_apigw.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/create_version_and_release_apigw.py index 75f232f7..8214eee1 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/create_version_and_release_apigw.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/create_version_and_release_apigw.py @@ -135,8 +135,8 @@ def handle(self, stage, title, comment, generate_sdks, *args, **kwargs): # create a sdk when released a new version if generate_sdks: self._generate_sdks( - releaser=releaser, - version=resource_version["version"], + releaser, + resource_version["version"], *args, **kwargs, ) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_apigw_public_key.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_apigw_public_key.py index 1f454a9a..2b095ac6 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_apigw_public_key.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_apigw_public_key.py @@ -8,7 +8,6 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -import sys from apigw_manager.apigw import helper from apigw_manager.apigw.command import FetchCommand diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_esb_public_key.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_esb_public_key.py index b083dcc3..737c66b3 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_esb_public_key.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/fetch_esb_public_key.py @@ -16,5 +16,5 @@ class Command(BaseCommand): """Get the esb public key and store it into the database""" def handle(self, api_name, *args, **kwargs): - for name in ["bk-esb", "apigw"]: - super(Command, self).handle(api_name=name, *args, **kwargs) + for gateway_name in ["bk-esb", "apigw"]: + super(Command, self).handle(gateway_name, *args, **kwargs) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_config.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_config.py index 441a1869..afa25106 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_config.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_config.py @@ -26,9 +26,9 @@ def add_arguments(self, parser): help="when definition is missing, use this maintainers as default maintainers", ) - def do(self, manager, definition, default_maintainers, *args, **kwargs): + def do(self, manager, definition, *args, **kwargs): if not definition.get("maintainers"): - definition["maintainers"] = default_maintainers + definition["maintainers"] = kwargs.get("default_maintainers", []) result = manager.sync_basic_config(**definition) print("API gateway basic synchronization completed, id %s, name %s" % (result["id"], result["name"])) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_strategies.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_strategies.py index 9d2accf8..67275e16 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_strategies.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_apigw_strategies.py @@ -29,7 +29,7 @@ def add_arguments(self, parser): help="strategy scope type", ) - def do(self, manager, definition, scope_type, *args, **kwargs): + def do(self, manager, definition, *args, **kwargs): logger.warning( "sync_apigw_strategies is deprecated starting with version 2.0.0, " "it will be removed in version 3.0.0, and now it does nothing." diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_resource_docs_by_archive.py b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_resource_docs_by_archive.py index c78751b8..0907d7d3 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_resource_docs_by_archive.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/management/commands/sync_resource_docs_by_archive.py @@ -29,7 +29,7 @@ def add_arguments(self, parser): help="do nothing when dir or archive file does not exist", ) - def do(self, manager, definition, safe_mode, *args, **kwargs): + def do(self, manager, definition, *args, **kwargs): # 1. 文档为归档文件 archivefile = definition.get("archivefile") if archivefile and os.path.isfile(archivefile): @@ -40,7 +40,7 @@ def do(self, manager, definition, safe_mode, *args, **kwargs): # 2. 指定文档目录,需归档后同步 basedir = definition.get("basedir") if not basedir or not os.path.isdir(basedir): - if safe_mode: + if kwargs.get("safe_mode"): return raise ValueError("the docs dir does not exist or is not a directory: %s" % basedir) diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/providers.py b/sdks/apigw-manager/src/apigw_manager/apigw/providers.py index 68f475cb..53b4362c 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/providers.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/providers.py @@ -37,10 +37,10 @@ class PublicKeyProvider(metaclass=abc.ABCMeta): def __init__(self, default_api_name: str): self.default_api_name = default_api_name - @abc.abstractclassmethod + @abc.abstractmethod def provide(self, api_name: str, jwt_issuer: Optional[str] = None) -> Optional[str]: """ - provide should return publick key base on api_name and jwt_issuer and + provide should return public key base on api_name and jwt_issuer and return None when process error """ @@ -119,7 +119,7 @@ def __init__( algorithm: str, allow_invalid_jwt_token: bool, public_key_provider: PublicKeyProvider, - **kwargs + **kwargs, ) -> None: self.jwt_key_name = jwt_key_name self.default_api_name = default_api_name @@ -127,7 +127,7 @@ def __init__( self.allow_invalid_jwt_token = allow_invalid_jwt_token self.public_key_provider = public_key_provider - @abc.abstractclassmethod + @abc.abstractmethod def provide(self, request: HttpRequest) -> Optional[DecodedJWT]: """ provide should extract jwt from rquest and return a DecodedJWT diff --git a/sdks/apigw-manager/src/apigw_manager/apigw/utils.py b/sdks/apigw-manager/src/apigw_manager/apigw/utils.py index 4c1964cf..9b58ce2a 100644 --- a/sdks/apigw-manager/src/apigw_manager/apigw/utils.py +++ b/sdks/apigw-manager/src/apigw_manager/apigw/utils.py @@ -16,7 +16,6 @@ from packaging.version import Version as _Version from apigw_manager.core import configuration -from bkapi_client_core.config import SettingKeys, settings def get_configuration(**kwargs): @@ -103,7 +102,7 @@ def _get_archived_files(cls, path): path = path if path.endswith(os.path.sep) else path + os.path.sep path_to_name = {} - for root, dirs, files in os.walk(path): + for root, _, files in os.walk(path): for name in files: file_path = os.path.join(root, name) path_to_name[file_path] = file_path[len(path) :] diff --git a/sdks/apigw-manager/src/apigw_manager/core/exceptions.py b/sdks/apigw-manager/src/apigw_manager/core/exceptions.py index 9ab88e26..9f60d6d8 100644 --- a/sdks/apigw-manager/src/apigw_manager/core/exceptions.py +++ b/sdks/apigw-manager/src/apigw_manager/core/exceptions.py @@ -20,16 +20,18 @@ def __str__(self): class ApiResponseError(Exception): """There was an exception that occurred while handling the response""" + def __init__(self, message): self.message = message def __str__(self): return self.message + class ApiResultError(ApiResponseError): def __init__(self, code, message): self.code = code self.message = message def __str__(self): - return "code: %s, %s" % (self.code, self.message) \ No newline at end of file + return "code: %s, %s" % (self.code, self.message) diff --git a/sdks/apigw-manager/src/apigw_manager/core/fetch.py b/sdks/apigw-manager/src/apigw_manager/core/fetch.py index d0d31681..2a7974a5 100644 --- a/sdks/apigw-manager/src/apigw_manager/core/fetch.py +++ b/sdks/apigw-manager/src/apigw_manager/core/fetch.py @@ -27,4 +27,4 @@ def latest_resource_version(self, *args, **kwargs): def list_resource_versions(self, *args, **kwargs): result = self._call(self.client.api.list_resource_versions, *args, **kwargs) - return self._parse_result(result, itemgetter("data")) \ No newline at end of file + return self._parse_result(result, itemgetter("data")) diff --git a/sdks/apigw-manager/src/apigw_manager/core/handler.py b/sdks/apigw-manager/src/apigw_manager/core/handler.py index 125161b4..9fc19593 100644 --- a/sdks/apigw-manager/src/apigw_manager/core/handler.py +++ b/sdks/apigw-manager/src/apigw_manager/core/handler.py @@ -13,13 +13,13 @@ import typing from bkapi.bk_apigateway.client import Client as BKAPIGatewayClient +from bkapi_client_core.exceptions import ResponseError from future.utils import raise_from from apigw_manager.core.exceptions import ApiException, ApiResponseError, ApiResultError -from bkapi_client_core.exceptions import ResponseError if typing.TYPE_CHECKING: - from apigw_manager.core import configuration + from apigw_manager.core import configuration # noqa logger = logging.getLogger(__name__) diff --git a/sdks/apigw-manager/src/apigw_manager/core/sync.py b/sdks/apigw-manager/src/apigw_manager/core/sync.py index e4612c08..2d165638 100644 --- a/sdks/apigw-manager/src/apigw_manager/core/sync.py +++ b/sdks/apigw-manager/src/apigw_manager/core/sync.py @@ -37,4 +37,4 @@ def sync_resource_docs_by_archive(self, *args, **kwargs): def add_related_apps(self, *args, **kwargs): result = self._call(self.client.api.add_related_apps, *args, **kwargs) - return self._parse_result(result, itemgetter("data")) \ No newline at end of file + return self._parse_result(result, itemgetter("data")) diff --git a/sdks/apigw-manager/src/apigw_manager/core/utils.py b/sdks/apigw-manager/src/apigw_manager/core/utils.py index d1d30717..419fa0da 100644 --- a/sdks/apigw-manager/src/apigw_manager/core/utils.py +++ b/sdks/apigw-manager/src/apigw_manager/core/utils.py @@ -23,5 +23,4 @@ def getter(r): def get_item(r, keys): """Get the value according to the keys""" - result = reduce(getitem, keys, r) # type: dict - return result + return reduce(getitem, keys, r) diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_apply_apigw_permissions.py b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_apply_apigw_permissions.py index 69703805..a9e8334d 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_apply_apigw_permissions.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_apply_apigw_permissions.py @@ -19,7 +19,6 @@ def command(): def test_do(mock_manager, command, configuration): - command.do( mock_manager, [ diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_create_version_and_release_apigw.py b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_create_version_and_release_apigw.py index 4f55b78c..335e6398 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_create_version_and_release_apigw.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_create_version_and_release_apigw.py @@ -12,7 +12,8 @@ import pytest import yaml -from packaging.version import parse as parse_version, InvalidVersion +from packaging.version import InvalidVersion +from packaging.version import parse as parse_version from apigw_manager.apigw.management.commands.create_version_and_release_apigw import Command @@ -72,7 +73,7 @@ def fake_resource_version(): @pytest.mark.parametrize( - "version, expected", + ("version", "expected"), [ (None, "None"), ("1.0.0", "1.0.0"), @@ -99,7 +100,7 @@ def test_parse_version_from_definition__error(command, version): @pytest.mark.parametrize( - "resource_version, expected", + ("resource_version", "expected"), [ (None, "None"), ({}, "None"), @@ -115,12 +116,12 @@ def test_parse_version_from_resource_version(command, resource_version, expected @pytest.mark.parametrize( - "defined_version, expected", + ("defined_version", "expected"), [ (None, "0.0.1"), ("1.0.0", "1.0.0"), ("v1.0.1", "1.0.1"), - ] + ], ) def test_fix_defined_version(command, defined_version, expected): result = command._fix_defined_version(defined_version and parse_version(defined_version)) @@ -128,14 +129,14 @@ def test_fix_defined_version(command, defined_version, expected): @pytest.mark.parametrize( - "defined_version, latest_version, is_dirty, expected", + ("defined_version", "latest_version", "is_dirty", "expected"), [ ("1.0.0", None, False, True), ("1.0.1", "1.0.0", False, True), ("1.0.1", "1.0.1", True, True), ("1.0.1", "1.0.1", False, False), ("1.0.1", "1.0.1+1", False, False), - ] + ], ) def test_should_create_resource_version(mocker, command, defined_version, latest_version, is_dirty, expected): manager = mocker.MagicMock(is_dirty=mocker.MagicMock(return_value=is_dirty)) @@ -149,7 +150,7 @@ def test_should_create_resource_version(mocker, command, defined_version, latest @pytest.mark.parametrize( - "defined_version, resource_version_exists, expected", + ("defined_version", "resource_version_exists", "expected"), [ ("1.0.1", False, "1.0.1"), ("0.0.1", False, "0.0.1"), diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_sync_apigw_resources.py b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_sync_apigw_resources.py index 54bbf277..7492d844 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_sync_apigw_resources.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/management/commands/test_sync_apigw_resources.py @@ -52,7 +52,7 @@ def test_do(mocker, configuration, command, manager, resource_signature_manager) @pytest.mark.parametrize( - "added, deleted, dirty", + ("added", "deleted", "dirty"), [ (True, True, True), (True, False, True), diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_authentication.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_authentication.py index 1cd9b987..e9067ed8 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_authentication.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_authentication.py @@ -80,11 +80,10 @@ def invalid_apigw_request(mock_request): class TestApiGatewayJWTMiddleware: @pytest.fixture(autouse=True) - def setup_middleware(self, mock_response, api_name): + def _setup_middleware(self, mock_response, api_name): self.middleware = authentication.ApiGatewayJWTMiddleware(mock_response) def test_default_config(self, api_name, jwt_algorithm): - assert isinstance(self.middleware.provider, DefaultJWTProvider) assert self.middleware.provider.default_api_name == api_name assert self.middleware.provider.algorithm == jwt_algorithm @@ -158,7 +157,7 @@ def test_init_without_settings(self, mock_response): class TestApiGatewayJWTAppMiddleware: @pytest.fixture(autouse=True) - def setup_middleware(self, mock_response): + def _setup_middleware(self, mock_response): self.middleware = authentication.ApiGatewayJWTAppMiddleware(mock_response) def test_make_app(self): @@ -177,7 +176,6 @@ def test_call_without_jwt(self, mock_request, mock_response): @pytest.mark.parametrize("field", ["app_code", "bk_app_code"]) def test_call_with_jwt(self, jwt_request, mock_response, jwt_app, field): - jwt_app = jwt_request.jwt.payload["app"] app_code = jwt_app.pop("app_code", None) or jwt_app.pop("bk_app_code", None) jwt_app[field] = app_code @@ -191,15 +189,15 @@ def test_call_with_jwt(self, jwt_request, mock_response, jwt_app, field): class TestApiGatewayJWTUserMiddleware: @pytest.fixture(autouse=True) - def setup_middleware(self, mock_response): + def _setup_middleware(self, mock_response): self.middleware = authentication.ApiGatewayJWTUserMiddleware(mock_response) @pytest.fixture(autouse=True) - def patch_authenticate(self, mocker): + def _patch_authenticate(self, mocker): self.authenticate_function = mocker.patch("django.contrib.auth.authenticate") @pytest.fixture(autouse=True) - def setup_user(self, mocker): + def _setup_user(self, mocker): self.user = mocker.MagicMock() def test_get_user(self, jwt_request): @@ -240,7 +238,7 @@ def test_call_with_jwt(self, jwt_request, mock_response, field): class TestUserModelBackend: @pytest.fixture(autouse=True) - def setup_backend(self, mocker): + def _setup_backend(self, mocker): self.user_maker = mocker.MagicMock() self.backend = authentication.UserModelBackend() self.backend.user_maker = self.user_maker diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_command.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_command.py index cceb8999..40d3eee5 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_command.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_command.py @@ -15,7 +15,7 @@ class TestApiCommand: @pytest.fixture(autouse=True) - def setup_command(self): + def _setup_command(self): self.command = command.ApiCommand() def test_get_configuration(self, configuration): @@ -35,7 +35,7 @@ def test_get_configuration_with_args(self, faker): class TestDefinitionCommand: @pytest.fixture(autouse=True) - def setup_command(self): + def _setup_command(self): self.command = command.DefinitionCommand() def test_get_context(self): diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_decorators.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_decorators.py index d7e655e7..3f6c69fe 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_decorators.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_decorators.py @@ -27,7 +27,7 @@ def mock_invalid_request(rf): def mock_valid_request(rf): req = rf.get("/") req.jwt = "jwt_token" - setattr(req, "jwt", "jwt_token") + req.jwt = "jwt_token" return req diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_helper.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_helper.py index 93a18de1..81e37063 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_helper.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_helper.py @@ -23,16 +23,16 @@ class TestDefinition: def test_load(self): definition = Definition.load( - 'a: {{a}}', + "a: {{a}}", { - 'a': 1, + "a": 1, }, ) - assert definition.loaded['a'] == 1 + assert definition.loaded["a"] == 1 @pytest.mark.parametrize( - ["namespace", "level"], + ("namespace", "level"), [ (None, 1), ("", 1), @@ -43,7 +43,7 @@ def test_load(self): ) def test_get(self, namespace, level): definition = Definition( - ''' + """ level: 1 a: level: 2 @@ -51,7 +51,7 @@ def test_get(self, namespace, level): level: 3 c: level: 4 - ''' + """ ) result = definition.get(namespace) @@ -60,7 +60,7 @@ def test_get(self, namespace, level): class TestContextManager: @pytest.fixture(autouse=True) - def setup_manager(self, faker): + def _setup_manager(self, faker): self.manager = ContextManager() self.manager.scope = faker.pystr() @@ -101,7 +101,7 @@ def test_set_value(self, faker): class TestPublicKeyManager: @pytest.fixture(autouse=True) - def setup_manager(self): + def _setup_manager(self): self.manager = PublicKeyManager() def test_get_not_found(self, api_name): @@ -160,7 +160,7 @@ def test_current(self, api_name, faker): class TestReleaseVersionManager: @pytest.fixture(autouse=True) - def setup_manager(self): + def _setup_manager(self): self.manager = ReleaseVersionManager() def test_increase(self, faker): @@ -172,7 +172,7 @@ def test_increase(self, faker): class TestResourceSignatureManager: @pytest.fixture(autouse=True) - def setup_manager(self): + def _setup_manager(self): self.manager = ResourceSignatureManager() def test_get_not_found(self, faker): diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_k8s_helper.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_k8s_helper.py index eef289ca..cf652585 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_k8s_helper.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_k8s_helper.py @@ -26,7 +26,7 @@ def public_key_secret(api_name, public_key): class TestSecretPublicKeyManager: @pytest.fixture(autouse=True) - def setup_manager(self, issuer, mocker, settings, public_key_secret): + def _setup_manager(self, issuer, mocker, settings, public_key_secret): mocker.patch("kubernetes.config.load_incluster_config") settings.APIGW_JWT_PUBLIC_KEY_SECRET_NAMESPACE = public_key_secret.metadata.namespace settings.APIGW_JWT_PUBLIC_KEY_SECRET_MAPPINGS = { diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_providers.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_providers.py index 42113709..1d72d14b 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_providers.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_providers.py @@ -36,7 +36,7 @@ def django_jwt_cache(settings, django_jwt_cache_name, mocker): class TestSettingsPublicKeyProvider: @pytest.fixture(autouse=True) - def setup_provider(self): + def _setup_provider(self): self.provider = SettingsPublicKeyProvider("testing") def test_default_api_name(self): diff --git a/sdks/apigw-manager/tests/apigw_manager/apigw/test_utils.py b/sdks/apigw-manager/tests/apigw_manager/apigw/test_utils.py index 37c370c8..e1c1073d 100644 --- a/sdks/apigw-manager/tests/apigw_manager/apigw/test_utils.py +++ b/sdks/apigw-manager/tests/apigw_manager/apigw/test_utils.py @@ -48,7 +48,7 @@ def test_jwt_provider_cls(self, settings, faker): assert configuration.jwt_provider_cls == settings.BK_APIGW_JWT_PROVIDER_CLS @pytest.mark.parametrize( - "kwargs, expected", + ("kwargs", "expected"), [ ( {}, @@ -73,7 +73,7 @@ def test_host_by_kwargs(self, settings, kwargs, expected): assert configuration.host == expected @pytest.mark.parametrize( - "fake_settings, expected", + ("fake_settings", "expected"), [ ( {}, diff --git a/sdks/apigw-manager/tests/apigw_manager/core/conftest.py b/sdks/apigw-manager/tests/apigw_manager/core/conftest.py index ceda3dfd..c2857338 100644 --- a/sdks/apigw-manager/tests/apigw_manager/core/conftest.py +++ b/sdks/apigw-manager/tests/apigw_manager/core/conftest.py @@ -8,42 +8,42 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ +import pytest from faker import Faker -from pytest import fixture from pytest_mock import MockerFixture from apigw_manager.core import configuration -@fixture() +@pytest.fixture() def config(): return configuration.Configuration() -@fixture() +@pytest.fixture() def bk_app_code(faker: Faker, config: configuration.Configuration): config.bk_app_code = faker.color return config.bk_app_code -@fixture() +@pytest.fixture() def bk_app_secret(faker: Faker, config: configuration.Configuration): config.bk_app_secret = faker.ssn return config.bk_app_secret -@fixture() +@pytest.fixture() def api_name(faker: Faker, config: configuration.Configuration): config.api_name = faker.color return config.api_name -@fixture() +@pytest.fixture() def api_cache(mocker: MockerFixture, config: configuration.Configuration): config.api_cache = mocker.MagicMock() return config.api_cache -@fixture() +@pytest.fixture() def api_instance(mocker: MockerFixture, config: configuration.Configuration): return mocker.MagicMock() diff --git a/sdks/apigw-manager/tests/apigw_manager/core/test_hander.py b/sdks/apigw-manager/tests/apigw_manager/core/test_hander.py index 2a963ce3..e434d3fa 100644 --- a/sdks/apigw-manager/tests/apigw_manager/core/test_hander.py +++ b/sdks/apigw-manager/tests/apigw_manager/core/test_hander.py @@ -8,25 +8,25 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ +import pytest +from bkapi_client_core.exceptions import HTTPResponseError from faker import Faker -from pytest import fixture, raises from apigw_manager.core.exceptions import ApiResponseError from apigw_manager.core.handler import Handler -from bkapi_client_core.exceptions import HTTPResponseError -@fixture() +@pytest.fixture() def handler(api_instance, config): return Handler(config) -@fixture() +@pytest.fixture() def operation_id(faker: Faker): return faker.color_name() -@fixture() +@pytest.fixture() def operation(mocker, operation_id): mock_operation = mocker.MagicMock() mock_operation.name = operation_id @@ -34,7 +34,7 @@ def operation(mocker, operation_id): return mock_operation -@fixture() +@pytest.fixture() def api_data(faker: Faker): return faker.pydict() @@ -90,12 +90,12 @@ def test_call_with_cache(self, handler: Handler, operation, operation_id, faker, def test_call_connect_error(self, handler: Handler, operation): operation.side_effect = HTTPResponseError() - with raises(ApiResponseError): + with pytest.raises(ApiResponseError): handler._call(operation) def test_call_server_error(self, handler: Handler, operation, mocker): operation.side_effect = HTTPResponseError(response=mocker.MagicMock(status_code=500)) - with raises(ApiResponseError): + with pytest.raises(ApiResponseError): handler._call(operation) def test_call_request_error(self, handler: Handler, operation, mocker): @@ -106,7 +106,7 @@ def test_call_request_error(self, handler: Handler, operation, mocker): ) ) - with raises(ApiResponseError): + with pytest.raises(ApiResponseError): handler._call(operation) def test_call_request_error_with_no_json(self, handler: Handler, operation, mocker): @@ -117,5 +117,5 @@ def test_call_request_error_with_no_json(self, handler: Handler, operation, mock ) ) - with raises(ApiResponseError): + with pytest.raises(ApiResponseError): handler._call(operation) diff --git a/sdks/apigw-manager/tests/apigw_manager/core/test_utils.py b/sdks/apigw-manager/tests/apigw_manager/core/test_utils.py index d90e30fc..59dd6cd5 100644 --- a/sdks/apigw-manager/tests/apigw_manager/core/test_utils.py +++ b/sdks/apigw-manager/tests/apigw_manager/core/test_utils.py @@ -8,12 +8,12 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from pytest import fixture, raises +import pytest from apigw_manager.core.utils import get_item, itemgetter -@fixture() +@pytest.fixture() def test_data(faker): return { "a": { @@ -32,7 +32,7 @@ def test_usage(self, test_data): def test_key_not_found(self, test_data): assert "nothing" not in test_data["a"] - with raises(KeyError): + with pytest.raises(KeyError): get_item(test_data, ["a", "nothing"]) diff --git a/sdks/apigw-manager/tests/conftest.py b/sdks/apigw-manager/tests/conftest.py index a983685d..132b768f 100644 --- a/sdks/apigw-manager/tests/conftest.py +++ b/sdks/apigw-manager/tests/conftest.py @@ -14,12 +14,12 @@ @pytest.fixture(autouse=True) -def reset_bkapi_settings(): +def _reset_bkapi_settings(): bkapi_settings.reset() @pytest.fixture(autouse=True) -def mark_django_db(db): +def _mark_django_db(db): pass @@ -37,7 +37,7 @@ def issuer(faker): @pytest.fixture() def private_key(): - return '''-----BEGIN RSA PRIVATE KEY----- + return """-----BEGIN RSA PRIVATE KEY----- MIICWgIBAAKBgER92Clgmc3ikcLbSjZFo2jC4mA+aP/kNKRKMud3AlDY0mPVbEu3 LeHov93zmvy1s5k5XTBPeAdRybKODQ0/jHOeXOOflaynDKZWknD8/WmU0O64Z/Qf IH7c1FhDYX1VUZhwPwpL0IxYJDIoCKzwBafPsIC4PUH+Lqyga3emP/v1AgMBAAEC @@ -51,17 +51,17 @@ def private_key(): WlRVbg5FYPz92Yjx0FFH0gLTm6FpNGmNoMuu16lkl8xXWQRKgof2oCondSZIldRT pe3xpxJvNIfri5u3AkA5VTxp77yXQ7Bra/F3eyLzQ8VzhhjXes+jxb6imag2Ry9o AuBDWd8zTFaIkV0Wl8BteGrMMfhLv0F9JxuDcZas ------END RSA PRIVATE KEY-----''' +-----END RSA PRIVATE KEY-----""" @pytest.fixture() def public_key(): - return '''-----BEGIN PUBLIC KEY----- + return """-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgER92Clgmc3ikcLbSjZFo2jC4mA+ aP/kNKRKMud3AlDY0mPVbEu3LeHov93zmvy1s5k5XTBPeAdRybKODQ0/jHOeXOOf laynDKZWknD8/WmU0O64Z/QfIH7c1FhDYX1VUZhwPwpL0IxYJDIoCKzwBafPsIC4 PUH+Lqyga3emP/v1AgMBAAE= ------END PUBLIC KEY-----''' +-----END PUBLIC KEY-----""" @pytest.fixture() @@ -95,31 +95,31 @@ def jwt_algorithm(): @pytest.fixture() def jwt_app(settings): return { - 'app_code': settings.BK_APP_CODE, - 'verified': True, + "app_code": settings.BK_APP_CODE, + "verified": True, } @pytest.fixture() def jwt_user(): return { - 'username': 'admin', - 'source_type': 'default', - 'verified': True, + "username": "admin", + "source_type": "default", + "verified": True, } @pytest.fixture() def jwt_decoded(jwt_app, jwt_user): return { - 'app': jwt_app, - 'user': jwt_user, + "app": jwt_app, + "user": jwt_user, } @pytest.fixture() def jwt_header(api_name, jwt_algorithm): - return {'alg': jwt_algorithm, 'kid': api_name, 'typ': 'JWT'} + return {"alg": jwt_algorithm, "kid": api_name, "typ": "JWT"} @pytest.fixture() diff --git a/sdks/apigw-manager/tests/demo/test_views.py b/sdks/apigw-manager/tests/demo/test_views.py index efa9758b..76cb70b7 100644 --- a/sdks/apigw-manager/tests/demo/test_views.py +++ b/sdks/apigw-manager/tests/demo/test_views.py @@ -27,9 +27,9 @@ def csrf_client(client: Client): @pytest.fixture(autouse=True) def user_object(jwt_user, faker): - User = get_user_model() + user_model = get_user_model() - return User.objects.create_user(username=jwt_user["username"], password=faker.color_name()) + return user_model.objects.create_user(username=jwt_user["username"], password=faker.color_name()) def test_jwt_info(csrf_client: Client, jwt_headers: dict, jwt_decoded: dict, api_name): diff --git a/sdks/apigw-manager/tox.ini b/sdks/apigw-manager/tox.ini index b27b896a..c8513665 100644 --- a/sdks/apigw-manager/tox.ini +++ b/sdks/apigw-manager/tox.ini @@ -5,7 +5,6 @@ envlist = py{36,37}-django{1,2,3}-pyjwt{1,2} [gh-actions] python = - 2.7: py27 3.6: py36 3.7: py37 diff --git a/sdks/bkapi-client-core/.pre-commit-config.yaml b/sdks/bkapi-client-core/.pre-commit-config.yaml deleted file mode 100644 index 9face6eb..00000000 --- a/sdks/bkapi-client-core/.pre-commit-config.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# See https://pre-commit.com/ for usage and config -fail_fast: true -repos: - - repo: local - hooks: - - id: isort - name: isort - stages: [commit] - language: system - entry: make isort - types: [python] - - - id: black - name: black - stages: [commit] - language: system - entry: make black - types: [python] - - - id: flake8 - name: flake8 - stages: [commit] - language: system - entry: make flake8 - types: [python] - exclude: setup.py - - - id: mypy - name: mypy - stages: [commit] - language: system - entry: make mypy - types: [python] - require_serial: true - - - id: pytest - name: pytest - stages: [commit] - language: system - entry: make test - types: [python] - pass_filenames: false diff --git a/sdks/bkapi-client-core/bkapi_client_core/apigateway/client.py b/sdks/bkapi-client-core/bkapi_client_core/apigateway/client.py index 07709aa4..c77421d9 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/apigateway/client.py +++ b/sdks/bkapi-client-core/bkapi_client_core/apigateway/client.py @@ -8,11 +8,11 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Optional +from typing import Optional # noqa from bkapi_client_core.client import BaseClient from bkapi_client_core.config import SettingKeys, settings -from bkapi_client_core.session import Session +from bkapi_client_core.session import Session # noqa from bkapi_client_core.utils import urljoin diff --git a/sdks/bkapi-client-core/bkapi_client_core/apigateway/django_helper.py b/sdks/bkapi-client-core/bkapi_client_core/apigateway/django_helper.py index 35adeb6e..ca72c8fb 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/apigateway/django_helper.py +++ b/sdks/bkapi-client-core/bkapi_client_core/apigateway/django_helper.py @@ -8,9 +8,9 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Optional, Type +from typing import Optional, Type # noqa -from bkapi_client_core.client import BaseClient +from bkapi_client_core.client import BaseClient # noqa from bkapi_client_core.config import SettingKeys, settings from bkapi_client_core.django_helper import get_client_by_request as _get_client_by_request from bkapi_client_core.django_helper import get_client_by_username as _get_client_by_username diff --git a/sdks/bkapi-client-core/bkapi_client_core/auth.py b/sdks/bkapi-client-core/bkapi_client_core/auth.py index eb0e1024..75f84e75 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/auth.py +++ b/sdks/bkapi-client-core/bkapi_client_core/auth.py @@ -9,10 +9,10 @@ * specific language governing permissions and limitations under the License. """ import json -from typing import Dict, Optional +from typing import Dict, Optional # noqa from requests.auth import AuthBase -from requests.models import PreparedRequest +from requests.models import PreparedRequest # noqa class BKApiAuthorization(AuthBase): diff --git a/sdks/bkapi-client-core/bkapi_client_core/base.py b/sdks/bkapi-client-core/bkapi_client_core/base.py index b016510c..3f6c2327 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/base.py +++ b/sdks/bkapi-client-core/bkapi_client_core/base.py @@ -8,9 +8,9 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional # noqa -from requests import Response +from requests import Response # noqa from typing_extensions import Protocol @@ -49,7 +49,7 @@ class OperationResource(object): def __init__( self, name="", # type: str - manager=None, # type: ManagerProtocol + manager=None, # type: Optional[ManagerProtocol] ): self.name = name self._manager = manager @@ -97,11 +97,11 @@ class Operation(OperationResource): def __init__( self, name="", # type: str - manager=None, # type: ManagerProtocol + manager=None, # type: Optional[ManagerProtocol] method="", # type: str path="", # type: str - bkapi_config=None, # type: Dict[str, Any] - **properties # type: Dict[str, Any] + bkapi_config=None, # type: Optional[Dict[str, Any]] + **properties, # type: Dict[str, Any] ): self.method = method self.path = path @@ -128,7 +128,7 @@ def __call__( timeout=None, # type: Optional[float] proxies=None, # type: Optional[Dict[str, Any]] verify=None, # type: Optional[bool] - **kwargs + **kwargs, ): """ Request to the api and return the structured result which parsed by the client. @@ -153,7 +153,7 @@ def __call__( timeout=timeout, proxies=proxies, verify=verify, - **kwargs + **kwargs, ), ) @@ -168,7 +168,7 @@ def request( timeout=None, # type: Optional[float] proxies=None, # type: Optional[Dict[str, Any]] verify=None, # type: Optional[bool] - **kwargs + **kwargs, ): # type: (...) -> Optional[Response] """ @@ -194,7 +194,7 @@ def request( timeout=timeout, proxies=proxies, verify=verify, - **kwargs + **kwargs, ), ) diff --git a/sdks/bkapi-client-core/bkapi_client_core/client.py b/sdks/bkapi-client-core/bkapi_client_core/client.py index 33beb24b..f216ca2c 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/client.py +++ b/sdks/bkapi-client-core/bkapi_client_core/client.py @@ -10,15 +10,15 @@ """ import json import logging -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional # noqa -from requests import Response +from requests import Response # noqa from requests.exceptions import HTTPError, RequestException from requests.sessions import merge_setting from requests.structures import CaseInsensitiveDict from bkapi_client_core.auth import BKApiAuthorization -from bkapi_client_core.base import Operation +from bkapi_client_core.base import Operation # noqa from bkapi_client_core.config import HookEvent from bkapi_client_core.exceptions import ( APIGatewayResponseError, @@ -47,7 +47,7 @@ def build_request_context( endpoint, # type: str data=None, # type: Any path="", # type: str - **request_context # type: Dict[str, Any] + **request_context, # type: Dict[str, Any] ): # type: (...) -> Dict[str, Any] self.build_url(request_context, endpoint, path) diff --git a/sdks/bkapi-client-core/bkapi_client_core/config.py b/sdks/bkapi-client-core/bkapi_client_core/config.py index 721a9034..fcb7d6d8 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/config.py +++ b/sdks/bkapi-client-core/bkapi_client_core/config.py @@ -9,7 +9,7 @@ * specific language governing permissions and limitations under the License. """ import os -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional # noqa try: from django.conf import settings as django_settings # noqa @@ -73,17 +73,17 @@ def get( if key in self._resolved: return self._resolved[key] - for key in self._aliases.get(key, [key]): - if self._settings and hasattr(self._settings, key): - value = self._resolved[key] = getattr(self._settings, key) + for _key in self._aliases.get(key, [key]): + if self._settings and hasattr(self._settings, _key): + value = self._resolved[_key] = getattr(self._settings, _key) return value - if self._env and key in self._env: - value = self._resolved[key] = self._env[key] + if self._env and _key in self._env: + value = self._resolved[_key] = self._env[_key] return value - if key in self._defaults: - value = self._resolved[key] = self._defaults[key] + if _key in self._defaults: + value = self._resolved[_key] = self._defaults[_key] return value return default diff --git a/sdks/bkapi-client-core/bkapi_client_core/django_helper.py b/sdks/bkapi-client-core/bkapi_client_core/django_helper.py index 26cd572c..de7ce853 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/django_helper.py +++ b/sdks/bkapi-client-core/bkapi_client_core/django_helper.py @@ -9,9 +9,9 @@ * specific language governing permissions and limitations under the License. """ import logging -from typing import Optional, Type +from typing import Optional, Type # noqa -from bkapi_client_core.client import BaseClient +from bkapi_client_core.client import BaseClient # noqa from bkapi_client_core.config import SettingKeys, settings from bkapi_client_core.exceptions import UserNotAuthenticated @@ -28,7 +28,7 @@ def _get_client_by_settings( bk_app_code=None, # type: Optional[str] bk_app_secret=None, # type: Optional[str] accept_language=None, # type: Optional[str] - **kwargs + **kwargs, ): """Returns a client according to the django settings""" client = client_cls(**kwargs) @@ -66,7 +66,7 @@ def _get_authorization_from_cookies(request, cookie_name_to_key): def get_client_by_request( client_cls, # type: Type[BaseClient] request, - **kwargs + **kwargs, ): """Returns a client according to the current request""" @@ -98,7 +98,7 @@ def get_access_token(): def get_client_by_username( client_cls, # type: Type[BaseClient] username, # type: str - **kwargs + **kwargs, ): """Returns a client according to the username""" diff --git a/sdks/bkapi-client-core/bkapi_client_core/esb/client.py b/sdks/bkapi-client-core/bkapi_client_core/esb/client.py index d3d1e0ad..8aa78f91 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/esb/client.py +++ b/sdks/bkapi-client-core/bkapi_client_core/esb/client.py @@ -8,10 +8,10 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Optional +from typing import Optional # noqa from bkapi_client_core.client import BaseClient -from bkapi_client_core.session import Session +from bkapi_client_core.session import Session # noqa class ESBClient(BaseClient): diff --git a/sdks/bkapi-client-core/bkapi_client_core/esb/django_helper.py b/sdks/bkapi-client-core/bkapi_client_core/esb/django_helper.py index 3c893018..9cac9179 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/esb/django_helper.py +++ b/sdks/bkapi-client-core/bkapi_client_core/esb/django_helper.py @@ -8,9 +8,9 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Optional, Type +from typing import Optional, Type # noqa -from bkapi_client_core.client import BaseClient +from bkapi_client_core.client import BaseClient # noqa from bkapi_client_core.config import SettingKeys, settings from bkapi_client_core.django_helper import get_client_by_request as _get_client_by_request from bkapi_client_core.django_helper import get_client_by_username as _get_client_by_username diff --git a/sdks/bkapi-client-core/bkapi_client_core/exceptions.py b/sdks/bkapi-client-core/bkapi_client_core/exceptions.py index d5dbb095..60da8ffe 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/exceptions.py +++ b/sdks/bkapi-client-core/bkapi_client_core/exceptions.py @@ -8,7 +8,7 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Optional +from typing import Optional # noqa from requests.exceptions import ( ChunkedEncodingError, diff --git a/sdks/bkapi-client-core/bkapi_client_core/prometheus.py b/sdks/bkapi-client-core/bkapi_client_core/prometheus.py index 02108132..3ad5e04f 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/prometheus.py +++ b/sdks/bkapi-client-core/bkapi_client_core/prometheus.py @@ -10,13 +10,13 @@ """ from functools import partial -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional # noqa -from prometheus_client import REGISTRY, CollectorRegistry, Counter, Histogram -from requests import Response +from prometheus_client import REGISTRY, CollectorRegistry, Counter, Histogram # noqa +from requests import Response # noqa from bkapi_client_core import session -from bkapi_client_core.base import Operation +from bkapi_client_core.base import Operation # noqa from bkapi_client_core.config import HookEvent from bkapi_client_core.utils import allow_fail @@ -72,7 +72,6 @@ def __init__( duration_buckets, # type: List[float] bytes_buckets, # type: List[float] ): - self.metric_requests_duration_seconds = Histogram( "bkapi_requests_duration_seconds", "Histogram of requests duration by operation, method", @@ -126,7 +125,7 @@ def response_hook( self, response, # type: Response bkapi_operation, # type: Operation - **kwargs # type: Any + **kwargs, # type: Any ): name = str(bkapi_operation) method = response.request.method @@ -205,7 +204,7 @@ def enable( """ Enable bkapi prometheus collector """ - global _GLOBAL_COLLECTOR + global _GLOBAL_COLLECTOR # noqa if _GLOBAL_COLLECTOR: return False @@ -218,3 +217,5 @@ def enable( bytes_buckets=bytes_buckets, ) _GLOBAL_COLLECTOR.enable_hooks() + + return True diff --git a/sdks/bkapi-client-core/bkapi_client_core/property.py b/sdks/bkapi-client-core/bkapi_client_core/property.py index 0d229ccc..97bb62b1 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/property.py +++ b/sdks/bkapi-client-core/bkapi_client_core/property.py @@ -8,7 +8,7 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ -from typing import Any, Type, TypeVar +from typing import Any, Type, TypeVar # noqa from typing_extensions import Protocol @@ -36,7 +36,7 @@ def __init__( self, cls, # type: Type[BindableProtocol] *args, # type: Any - **kwargs # type: Any + **kwargs, # type: Any ): self._name = "" self._property_id = "_bind_property_id_%s" % id(self) diff --git a/sdks/bkapi-client-core/bkapi_client_core/session.py b/sdks/bkapi-client-core/bkapi_client_core/session.py index 1273718d..2add4b09 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/session.py +++ b/sdks/bkapi-client-core/bkapi_client_core/session.py @@ -9,9 +9,9 @@ * specific language governing permissions and limitations under the License. """ import string -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional # noqa -from requests import Request +from requests import Request # noqa from requests import Session as RequestSession from requests.hooks import dispatch_hook from requests.models import RequestHooksMixin @@ -100,7 +100,7 @@ def handle( url, # type: str path_params=None, # type: Optional[Dict[str, Any]] timeout=None, # type: Optional[float] - **kwargs # type: Any + **kwargs, # type: Any ): render = _UrlRender(url, self.path_params) rendered_url = render.render(path_params) @@ -138,14 +138,13 @@ def prepare_request( request, # type: Request ): request = self.dispatch_hook(HookEvent.REQUEST, request) - prepared_request = super(Session, self).prepare_request(request) - return prepared_request + return super(Session, self).prepare_request(request) def dispatch_hook( self, event, # str data, # Any - **extras # type: Any + **extras, # type: Any ): data = dispatch_hook(event, _SESSION_HOOKS, data, **extras) return dispatch_hook(event, self.hooks, data, **extras) diff --git a/sdks/bkapi-client-core/bkapi_client_core/utils.py b/sdks/bkapi-client-core/bkapi_client_core/utils.py index ebb02056..fe3dad00 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/utils.py +++ b/sdks/bkapi-client-core/bkapi_client_core/utils.py @@ -11,10 +11,10 @@ import copy import json from functools import wraps -from typing import Callable, Optional, Type, TypeVar +from typing import Callable, Optional, Type, TypeVar # noqa import curlify -import requests +import requests # noqa def urljoin(base_url, path): diff --git a/sdks/bkapi-client-core/poetry.lock b/sdks/bkapi-client-core/poetry.lock index c7b4fc1d..1b75e078 100644 --- a/sdks/bkapi-client-core/poetry.lock +++ b/sdks/bkapi-client-core/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" version = "3.7.4.post0" description = "Async http client/server framework (asyncio)" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -63,28 +62,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "async-timeout" version = "3.0.1" description = "Timeout context manager for asyncio programs" -category = "dev" optional = false python-versions = ">=3.5.3" files = [ @@ -97,28 +78,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "attrs" version = "21.2.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -141,7 +104,6 @@ reference = "tencent" name = "backports.entry-points-selectable" version = "1.1.0" description = "Compatibility shim providing selectable entry points for older implementations" -category = "dev" optional = false python-versions = ">=2.7" files = [ @@ -161,32 +123,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "backports.functools-lru-cache" -version = "1.6.4" -description = "Backport of functools.lru_cache" -category = "dev" -optional = false -python-versions = ">=2.6" -files = [ - {file = "backports.functools_lru_cache-1.6.4-py2.py3-none-any.whl", hash = "sha256:dbead04b9daa817909ec64e8d2855fb78feafe0b901d4568758e3a60559d8978"}, - {file = "backports.functools_lru_cache-1.6.4.tar.gz", hash = "sha256:d5ed2169378b67d3c545e5600d363a923b09c456dab1593914935a68ad478271"}, -] - -[package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "bkoauth" version = "0.0.24" description = "blueking oauth" -category = "main" optional = true python-versions = "*" files = [ @@ -202,44 +142,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "black" -version = "21.6b0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.6.2" -files = [ - {file = "black-21.6b0-py3-none-any.whl", hash = "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"}, - {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"}, -] - -[package.dependencies] -appdirs = "*" -click = ">=7.1.2" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.8.1,<1" -regex = ">=2020.1.8" -toml = ">=0.10.1" -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""} -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] -python2 = ["typed-ast (>=1.4.2)"] -uvloop = ["uvloop (>=0.15.2)"] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "cerberus" version = "1.3.4" description = "Lightweight, extensible schema and data validation tool for Python dictionaries." -category = "dev" optional = false python-versions = ">=2.7" files = [ @@ -258,7 +164,6 @@ reference = "tencent" name = "certifi" version = "2021.5.30" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = "*" files = [ @@ -275,7 +180,6 @@ reference = "tencent" name = "cfgv" version = "3.3.0" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -292,7 +196,6 @@ reference = "tencent" name = "chardet" version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -309,7 +212,6 @@ reference = "tencent" name = "charset-normalizer" version = "2.0.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.5.0" files = [ @@ -325,32 +227,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "click" -version = "8.0.1" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -364,37 +244,18 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "configparser" -version = "4.0.2" -description = "Updated configparser from Python 3.7 for Python 2.6+." -category = "dev" +name = "commonmark" +version = "0.9.1" +description = "Python parser for the CommonMark Markdown spec" optional = false -python-versions = ">=2.6" +python-versions = "*" files = [ - {file = "configparser-4.0.2-py2.py3-none-any.whl", hash = "sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c"}, - {file = "configparser-4.0.2.tar.gz", hash = "sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"}, + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] [package.extras] -docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2)", "pytest-flake8"] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - -[[package]] -name = "contextlib2" -version = "0.6.0.post1" -description = "Backports and enhancements for the contextlib module" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"}, - {file = "contextlib2-0.6.0.post1.tar.gz", hash = "sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e"}, -] +test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [package.source] type = "legacy" @@ -405,7 +266,6 @@ reference = "tencent" name = "coverage" version = "5.5" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" files = [ @@ -463,6 +323,9 @@ files = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] +[package.dependencies] +toml = {version = "*", optional = true, markers = "extra == \"toml\""} + [package.extras] toml = ["toml"] @@ -475,7 +338,6 @@ reference = "tencent" name = "curlify" version = "2.2.1" description = "Library to convert python requests object to curl command." -category = "main" optional = false python-versions = "*" files = [ @@ -494,7 +356,6 @@ reference = "tencent" name = "dataclasses" version = "0.8" description = "A backport of the dataclasses module for Python 3.6" -category = "dev" optional = false python-versions = ">=3.6, <3.7" files = [ @@ -511,7 +372,6 @@ reference = "tencent" name = "dephell" version = "0.8.3" description = "Dependency resolution for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -561,7 +421,6 @@ reference = "tencent" name = "dephell-archive" version = "0.1.7" description = "pathlib for archives" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -581,7 +440,6 @@ reference = "tencent" name = "dephell-argparse" version = "0.1.3" description = "Argparse on steroids: groups, commands, colors." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -598,7 +456,6 @@ reference = "tencent" name = "dephell-changelogs" version = "0.0.1" description = "Find changelog for github repository, local dir, parse changelog" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -621,7 +478,6 @@ reference = "tencent" name = "dephell-discover" version = "0.2.10" description = "Find project modules and data files (packages and package_data for setup.py)." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -641,7 +497,6 @@ reference = "tencent" name = "dephell-licenses" version = "0.1.7" description = "Get info about OSS licenses" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -662,7 +517,6 @@ reference = "tencent" name = "dephell-links" version = "0.1.5" description = "Parse dependency links" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -682,7 +536,6 @@ reference = "tencent" name = "dephell-markers" version = "1.0.3" description = "Work with environment markers (PEP-496)" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -704,7 +557,6 @@ reference = "tencent" name = "dephell-pythons" version = "0.1.15" description = "Work with python versions" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -726,7 +578,6 @@ reference = "tencent" name = "dephell-setuptools" version = "0.2.4" description = "Read metainfo from setup.py" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -749,7 +600,6 @@ reference = "tencent" name = "dephell-shells" version = "0.1.5" description = "activate virtual environment for current shell" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -771,7 +621,6 @@ reference = "tencent" name = "dephell-specifier" version = "0.2.2" description = "Work with version specifiers." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -791,7 +640,6 @@ reference = "tencent" name = "dephell-venvs" version = "0.1.18" description = "Manage virtual environments" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -813,7 +661,6 @@ reference = "tencent" name = "dephell-versioning" version = "0.1.2" description = "Library for bumping project version like a pro" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -833,7 +680,6 @@ reference = "tencent" name = "distlib" version = "0.3.2" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -850,7 +696,6 @@ reference = "tencent" name = "django" version = "1.11.20" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." -category = "main" optional = false python-versions = "*" files = [ @@ -874,7 +719,6 @@ reference = "tencent" name = "docutils" version = "0.17.1" description = "Docutils -- Python Documentation Utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -888,39 +732,18 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "faker" -version = "3.0.1" -description = "Faker is a Python package that generates fake data for you." -category = "dev" +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" files = [ - {file = "Faker-3.0.1-py2.py3-none-any.whl", hash = "sha256:6eb3581e990e36ef6f1cf37f70f9a799e119e1a7b94a6062a14f1b8d781c67e4"}, - {file = "Faker-3.0.1.tar.gz", hash = "sha256:c7f7466cb9ba58d582f713494acdb5ebcc462336c5e38c5230b0cdab37069985"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] -[package.dependencies] -ipaddress = {version = "*", markers = "python_version < \"3.3\""} -python-dateutil = ">=2.4" -six = ">=1.10" -text-unidecode = "1.3" - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - -[[package]] -name = "filelock" -version = "3.0.12" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, -] +[package.extras] +test = ["pytest (>=6)"] [package.source] type = "legacy" @@ -928,22 +751,19 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "flake8" -version = "3.9.2" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" +name = "faker" +version = "14.2.1" +description = "Faker is a Python package that generates fake data for you." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, + {file = "Faker-14.2.1-py3-none-any.whl", hash = "sha256:2e28aaea60456857d4ce95dd12aed767769537ad23d13d51a545cd40a654e9d9"}, + {file = "Faker-14.2.1.tar.gz", hash = "sha256:daad7badb4fd916bd047b28c8459ef4689e4fe6acf61f6dfebee8cc602e4d009"}, ] [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" +python-dateutil = ">=2.4" +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [package.source] type = "legacy" @@ -951,15 +771,14 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "funcsigs" -version = "1.0.2" -description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+" -category = "dev" +name = "filelock" +version = "3.0.12" +description = "A platform independent file lock." optional = false python-versions = "*" files = [ - {file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"}, - {file = "funcsigs-1.0.2.tar.gz", hash = "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"}, + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, ] [package.source] @@ -971,7 +790,6 @@ reference = "tencent" name = "identify" version = "2.2.11" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -991,7 +809,6 @@ reference = "tencent" name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1008,7 +825,6 @@ reference = "tencent" name = "idna" version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1025,7 +841,6 @@ reference = "tencent" name = "importlib-metadata" version = "2.1.1" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -1034,9 +849,6 @@ files = [ ] [package.dependencies] -configparser = {version = ">=3.5", markers = "python_version < \"3\""} -contextlib2 = {version = "*", markers = "python_version < \"3\""} -pathlib2 = {version = "*", markers = "python_version < \"3\""} zipp = ">=0.5" [package.extras] @@ -1049,40 +861,16 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "ipaddress" -version = "1.0.23" -description = "IPv4/IPv6 manipulation library" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "ipaddress-1.0.23-py2.py3-none-any.whl", hash = "sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc"}, - {file = "ipaddress-1.0.23.tar.gz", hash = "sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - -[[package]] -name = "isort" -version = "5.9.2" -description = "A Python utility / library to sort Python imports." -category = "dev" +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.7" files = [ - {file = "isort-5.9.2-py3-none-any.whl", hash = "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813"}, - {file = "isort-5.9.2.tar.gz", hash = "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [package.source] type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" @@ -1092,7 +880,6 @@ reference = "tencent" name = "jinja2" version = "3.0.1" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1115,7 +902,6 @@ reference = "tencent" name = "m2r" version = "0.2.1" description = "Markdown and reStructuredText in a single file." -category = "dev" optional = false python-versions = "*" files = [ @@ -1135,7 +921,6 @@ reference = "tencent" name = "markupsafe" version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1215,28 +1000,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "mistune" version = "0.8.4" description = "The fastest markdown parser in pure Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -1249,37 +1016,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "mock" -version = "3.0.5" -description = "Rolling backport of unittest.mock for all Pythons" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "mock-3.0.5-py2.py3-none-any.whl", hash = "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8"}, - {file = "mock-3.0.5.tar.gz", hash = "sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3"}, -] - -[package.dependencies] -funcsigs = {version = ">=1", markers = "python_version < \"3.3\""} -six = "*" - -[package.extras] -build = ["blurb", "twine", "wheel"] -docs = ["sphinx"] -test = ["pytest", "pytest-cov"] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "more-itertools" version = "5.0.0" description = "More routines for operating on iterables, beyond itertools" -category = "dev" optional = false python-versions = "*" files = [ @@ -1300,7 +1040,6 @@ reference = "tencent" name = "multidict" version = "5.1.0" description = "multidict implementation" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1350,46 +1089,46 @@ reference = "tencent" [[package]] name = "mypy" -version = "0.910" +version = "0.971" description = "Optional static typing for Python" -category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, - {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, - {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"}, - {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"}, - {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"}, - {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"}, - {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"}, - {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"}, - {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"}, - {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"}, - {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"}, - {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"}, - {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"}, - {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"}, - {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"}, - {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"}, - {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"}, - {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"}, - {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"}, - {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"}, - {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"}, - {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"}, - {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"}, + {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"}, + {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"}, + {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"}, + {file = "mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"}, + {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"}, + {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"}, + {file = "mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"}, + {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"}, + {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"}, + {file = "mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"}, + {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"}, + {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"}, + {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"}, + {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"}, + {file = "mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"}, + {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"}, + {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"}, + {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"}, + {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"}, + {file = "mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"}, + {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"}, + {file = "mypy-0.971-py3-none-any.whl", hash = "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"}, + {file = "mypy-0.971.tar.gz", hash = "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"}, ] [package.dependencies] -mypy-extensions = ">=0.4.3,<0.5.0" -toml = "*" -typed-ast = {version = ">=1.4.0,<1.5.0", markers = "python_version < \"3.8\""} -typing-extensions = ">=3.7.4" +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} +typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<1.5.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] [package.source] type = "legacy" @@ -1400,7 +1139,6 @@ reference = "tencent" name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" optional = false python-versions = "*" files = [ @@ -1417,7 +1155,6 @@ reference = "tencent" name = "nodeenv" version = "1.6.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = "*" files = [ @@ -1434,7 +1171,6 @@ reference = "tencent" name = "packaging" version = "20.9" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1450,49 +1186,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "pathlib2" -version = "2.3.6" -description = "Object-oriented filesystem paths" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "pathlib2-2.3.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, - {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, -] - -[package.dependencies] -scandir = {version = "*", markers = "python_version < \"3.5\""} -six = "*" - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - -[[package]] -name = "pathspec" -version = "0.8.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, - {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" files = [ @@ -1512,7 +1209,6 @@ reference = "tencent" name = "pip" version = "19.3.1" description = "The PyPA recommended tool for installing Python packages." -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -1529,7 +1225,6 @@ reference = "tencent" name = "platformdirs" version = "2.0.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1546,7 +1241,6 @@ reference = "tencent" name = "pluggy" version = "0.13.1" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1567,14 +1261,13 @@ reference = "tencent" [[package]] name = "pre-commit" -version = "2.13.0" +version = "2.20.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" files = [ - {file = "pre_commit-2.13.0-py2.py3-none-any.whl", hash = "sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4"}, - {file = "pre_commit-2.13.0.tar.gz", hash = "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378"}, + {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, + {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, ] [package.dependencies] @@ -1595,7 +1288,6 @@ reference = "tencent" name = "prometheus-client" version = "0.12.0" description = "Python client for the Prometheus monitoring system." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1615,7 +1307,6 @@ reference = "tencent" name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -1632,7 +1323,6 @@ reference = "tencent" name = "py" version = "1.10.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1646,33 +1336,18 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "pycodestyle" -version = "2.7.0" -description = "Python style guide checker" -category = "dev" +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" files = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, ] -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - -[[package]] -name = "pyflakes" -version = "2.3.1" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, -] +[package.extras] +plugins = ["importlib-metadata"] [package.source] type = "legacy" @@ -1683,7 +1358,6 @@ reference = "tencent" name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1696,58 +1370,28 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "pyproject-flake8" -version = "0.0.1a2" -description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "pyproject-flake8-0.0.1a2.tar.gz", hash = "sha256:bdeca37f78ecd34bd64a49d3657d53d099f5445831071a31c46e1fe20cd61461"}, - {file = "pyproject_flake8-0.0.1a2-py2.py3-none-any.whl", hash = "sha256:e61ed1dc088e9f9f8a7170967ac4ec135acfef3a59ab9738c7b58cc11f294a7e"}, -] - -[package.dependencies] -flake8 = "*" -toml = "*" - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "pytest" -version = "4.6.11" +version = "7.4.3" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = ">=3.7" files = [ - {file = "pytest-4.6.11-py2.py3-none-any.whl", hash = "sha256:a00a7d79cbbdfa9d21e7d0298392a8dd4123316bfac545075e6f8f24c94d8c97"}, - {file = "pytest-4.6.11.tar.gz", hash = "sha256:50fa82392f2120cc3ec2ca0a75ee615be4c479e66669789771f1758332be4353"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] -atomicwrites = ">=1.0" -attrs = ">=17.4.0" -colorama = {version = "*", markers = "sys_platform == \"win32\" and python_version != \"3.4\""} -funcsigs = {version = ">=1.0", markers = "python_version < \"3.0\""} +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -more-itertools = [ - {version = ">=4.0.0,<6.0.0", markers = "python_version <= \"2.7\""}, - {version = ">=4.0.0", markers = "python_version > \"2.7\""}, -] +iniconfig = "*" packaging = "*" -pathlib2 = {version = ">=2.2.0", markers = "python_version < \"3.6\""} -pluggy = ">=0.12,<1.0" -py = ">=1.5.0" -six = ">=1.10.0" -wcwidth = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [package.source] type = "legacy" @@ -1756,20 +1400,18 @@ reference = "tencent" [[package]] name = "pytest-cov" -version = "2.12.1" +version = "4.1.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, - {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] -coverage = ">=5.2.1" +coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" -toml = "*" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] @@ -1781,23 +1423,21 @@ reference = "tencent" [[package]] name = "pytest-django" -version = "3.10.0" +version = "4.5.2" description = "A Django plugin for pytest." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" files = [ - {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"}, - {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"}, + {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, + {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, ] [package.dependencies] -pathlib2 = {version = "*", markers = "python_version < \"3.4\""} -pytest = ">=3.6" +pytest = ">=5.4.0" [package.extras] docs = ["sphinx", "sphinx-rtd-theme"] -testing = ["Django", "django-configurations (>=2.0)", "six"] +testing = ["Django", "django-configurations (>=2.0)"] [package.source] type = "legacy" @@ -1805,18 +1445,21 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "pytest-faker" -version = "2.0.0" -description = "Faker integration with the pytest framework." -category = "dev" +name = "pytest-mock" +version = "3.11.1" +description = "Thin-wrapper around the mock package for easier use with pytest" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "pytest-faker-2.0.0.tar.gz", hash = "sha256:6b37bb89d94f96552bfa51f8e8b89d32addded8ddb58a331488299ef0137d9b6"}, + {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, + {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, ] [package.dependencies] -Faker = ">=0.7.3" +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] [package.source] type = "legacy" @@ -1824,23 +1467,19 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "pytest-mock" -version = "2.0.0" -description = "Thin-wrapper around the mock package for easier use with py.test" -category = "dev" +name = "pytest-pretty" +version = "1.2.0" +description = "pytest plugin for printing summary data as I want it" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" files = [ - {file = "pytest-mock-2.0.0.tar.gz", hash = "sha256:b35eb281e93aafed138db25c8772b95d3756108b601947f89af503f8c629413f"}, - {file = "pytest_mock-2.0.0-py2.py3-none-any.whl", hash = "sha256:cb67402d87d5f53c579263d37971a164743dc33c159dfb4fb4a86f37c5552307"}, + {file = "pytest_pretty-1.2.0-py3-none-any.whl", hash = "sha256:6f79122bf53864ae2951b6c9e94d7a06a87ef753476acd4588aeac018f062036"}, + {file = "pytest_pretty-1.2.0.tar.gz", hash = "sha256:105a355f128e392860ad2c478ae173ff96d2f03044692f9818ff3d49205d3a60"}, ] [package.dependencies] -mock = {version = "*", markers = "python_version < \"3.0\""} -pytest = ">=2.7" - -[package.extras] -dev = ["pre-commit", "tox"] +pytest = ">=7" +rich = ">=12" [package.source] type = "legacy" @@ -1851,7 +1490,6 @@ reference = "tencent" name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1871,7 +1509,6 @@ reference = "tencent" name = "pytz" version = "2021.1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -1888,7 +1525,6 @@ reference = "tencent" name = "pyyaml" version = "5.4.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -1928,83 +1564,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "regex" -version = "2021.7.6" -description = "Alternative regular expression module, to replace re." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf1d2d183abc7faa101ebe0b8d04fd19cb9138820abc8589083035c9440b8ca6"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1947e7de155063e1c495c50590229fb98720d4c383af5031bbcb413db33fa1be"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17d8a3f99b18d87ac54a449b836d485cc8c195bb6f5e4379c84c8519045facc9"}, - {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d30895ec80cc80358392841add9dde81ea1d54a4949049269115e6b0555d0498"}, - {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"}, - {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"}, - {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8244c681018423a0d1784bc6b9af33bdf55f2ab8acb1f3cd9dd83d90e0813253"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a4c742089faf0e51469c6a1ad7e3d3d21afae54a16a6cead85209dfe0a1ce65"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914e626dc8e75fe4fc9b7214763f141d9f40165d00dfe680b104fa1b24063bbf"}, - {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fabb19c82ecf39832a3f5060dfea9a7ab270ef156039a1143a29a83a09a62de"}, - {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"}, - {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"}, - {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfc0957c4a4b91eff5ad036088769e600a25774256cd0e1154378591ce573f08"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efb4af05fa4d2fc29766bf516f1f5098d6b5c3ed846fde980c18bf8646ad3979"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7423aca7cc30a6228ccdcf2ea76f12923d652c5c7c6dc1959a0b004e308f39fb"}, - {file = "regex-2021.7.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb9834c1e77493efd7343b8e38950dee9797d2d6f2d5fd91c008dfaef64684b9"}, - {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"}, - {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"}, - {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598ee917dbe961dcf827217bf2466bb86e4ee5a8559705af57cbabb3489dd37e"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:56fc7045a1999a8d9dd1896715bc5c802dfec5b9b60e883d2cbdecb42adedea4"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8363ac90ea63c3dd0872dfdb695f38aff3334bfa5712cffb238bd3ffef300e3"}, - {file = "regex-2021.7.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:716a6db91b3641f566531ffcc03ceec00b2447f0db9942b3c6ea5d2827ad6be3"}, - {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"}, - {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"}, - {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"}, -] - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "requests" version = "2.26.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2035,7 +1598,6 @@ reference = "tencent" name = "requests-mock" version = "1.9.3" description = "Mock out responses from the requests package" -category = "dev" optional = false python-versions = "*" files = [ @@ -2056,11 +1618,34 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" +[[package]] +name = "rich" +version = "12.0.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.6.2,<4.0.0" +files = [ + {file = "rich-12.0.1-py3-none-any.whl", hash = "sha256:ce5c714e984a2d185399e4e1dd1f8b2feacb7cecfc576f1522425643a36a57ea"}, + {file = "rich-12.0.1.tar.gz", hash = "sha256:3fba9dd15ebe048e2795a02ac19baee79dc12cc50b074ef70f2958cd651b59a9"}, +] + +[package.dependencies] +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" +typing-extensions = {version = ">=3.7.4,<5.0", markers = "python_version < \"3.8\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] + +[package.source] +type = "legacy" +url = "https://mirrors.cloud.tencent.com/pypi/simple" +reference = "tencent" + [[package]] name = "ruamel.yaml" version = "0.17.10" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -2084,7 +1669,6 @@ reference = "tencent" name = "ruamel.yaml.clib" version = "0.2.6" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2126,24 +1710,29 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "scandir" -version = "1.10.0" -description = "scandir, a better directory iterator and faster os.walk()" -category = "dev" +name = "ruff" +version = "0.1.4" +description = "An extremely fast Python linter and code formatter, written in Rust." optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "scandir-1.10.0-cp27-cp27m-win32.whl", hash = "sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188"}, - {file = "scandir-1.10.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"}, - {file = "scandir-1.10.0-cp34-cp34m-win32.whl", hash = "sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f"}, - {file = "scandir-1.10.0-cp34-cp34m-win_amd64.whl", hash = "sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e"}, - {file = "scandir-1.10.0-cp35-cp35m-win32.whl", hash = "sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f"}, - {file = "scandir-1.10.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32"}, - {file = "scandir-1.10.0-cp36-cp36m-win32.whl", hash = "sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022"}, - {file = "scandir-1.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4"}, - {file = "scandir-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173"}, - {file = "scandir-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d"}, - {file = "scandir-1.10.0.tar.gz", hash = "sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae"}, + {file = "ruff-0.1.4-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:864958706b669cce31d629902175138ad8a069d99ca53514611521f532d91495"}, + {file = "ruff-0.1.4-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9fdd61883bb34317c788af87f4cd75dfee3a73f5ded714b77ba928e418d6e39e"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4eaca8c9cc39aa7f0f0d7b8fe24ecb51232d1bb620fc4441a61161be4a17539"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9a1301dc43cbf633fb603242bccd0aaa34834750a14a4c1817e2e5c8d60de17"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e8db8ab6f100f02e28b3d713270c857d370b8d61871d5c7d1702ae411df683"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:80fea754eaae06335784b8ea053d6eb8e9aac75359ebddd6fee0858e87c8d510"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bc02a480d4bfffd163a723698da15d1a9aec2fced4c06f2a753f87f4ce6969c"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862811b403063765b03e716dac0fda8fdbe78b675cd947ed5873506448acea4"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58826efb8b3efbb59bb306f4b19640b7e366967a31c049d49311d9eb3a4c60cb"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fdfd453fc91d9d86d6aaa33b1bafa69d114cf7421057868f0b79104079d3e66e"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e8791482d508bd0b36c76481ad3117987301b86072158bdb69d796503e1c84a8"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01206e361021426e3c1b7fba06ddcb20dbc5037d64f6841e5f2b21084dc51800"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:645591a613a42cb7e5c2b667cbefd3877b21e0252b59272ba7212c3d35a5819f"}, + {file = "ruff-0.1.4-py3-none-win32.whl", hash = "sha256:99908ca2b3b85bffe7e1414275d004917d1e0dfc99d497ccd2ecd19ad115fd0d"}, + {file = "ruff-0.1.4-py3-none-win_amd64.whl", hash = "sha256:1dfd6bf8f6ad0a4ac99333f437e0ec168989adc5d837ecd38ddb2cc4a2e3db8a"}, + {file = "ruff-0.1.4-py3-none-win_arm64.whl", hash = "sha256:d98ae9ebf56444e18a3e3652b3383204748f73e247dea6caaf8b52d37e6b32da"}, + {file = "ruff-0.1.4.tar.gz", hash = "sha256:21520ecca4cc555162068d87c747b8f95e1e95f8ecfcbbe59e8dd00710586315"}, ] [package.source] @@ -2155,7 +1744,6 @@ reference = "tencent" name = "setuptools" version = "65.6.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2177,7 +1765,6 @@ reference = "tencent" name = "shellingham" version = "1.4.0" description = "Tool to Detect Surrounding Shell" -category = "dev" optional = false python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" files = [ @@ -2194,7 +1781,6 @@ reference = "tencent" name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2211,7 +1797,6 @@ reference = "tencent" name = "termcolor" version = "1.1.0" description = "ANSII Color formatting for output in terminal." -category = "dev" optional = false python-versions = "*" files = [ @@ -2224,15 +1809,14 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "text-unidecode" -version = "1.3" -description = "The most basic Text::Unidecode port" -category = "dev" +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" optional = false -python-versions = "*" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, - {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] [package.source] @@ -2241,15 +1825,14 @@ url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" [[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.7" files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] [package.source] @@ -2261,7 +1844,6 @@ reference = "tencent" name = "tomlkit" version = "0.7.2" description = "Style preserving TOML library" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2278,7 +1860,6 @@ reference = "tencent" name = "tox" version = "3.24.0" description = "tox is a generic virtualenv management and test command line tool" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -2310,7 +1891,6 @@ reference = "tencent" name = "typed-ast" version = "1.4.3" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = "*" files = [ @@ -2355,7 +1935,6 @@ reference = "tencent" name = "types-requests" version = "2.25.0" description = "Typing stubs for requests" -category = "dev" optional = false python-versions = "*" files = [ @@ -2368,13 +1947,28 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" +[[package]] +name = "types-six" +version = "1.16.21.9" +description = "Typing stubs for six" +optional = false +python-versions = "*" +files = [ + {file = "types-six-1.16.21.9.tar.gz", hash = "sha256:746e6c25b8c48b3c8ab9efe7f68022839111de423d35ba4b206b88b12d75f233"}, + {file = "types_six-1.16.21.9-py3-none-any.whl", hash = "sha256:1591a09430a3035326da5fdb71692d0b3cc36b25a440cc5929ca6241f3984705"}, +] + +[package.source] +type = "legacy" +url = "https://mirrors.cloud.tencent.com/pypi/simple" +reference = "tencent" + [[package]] name = "typing" version = "3.10.0.0" description = "Type Hints for Python" -category = "main" optional = false -python-versions = ">=2.7,<3.0.0 || >=3.4.0,<3.5" +python-versions = ">=2.7,<3.0.dev0 || ==3.4.*" files = [ {file = "typing-3.10.0.0-py2-none-any.whl", hash = "sha256:c7219ef20c5fbf413b4567092adfc46fa6203cb8454eda33c3fc1afe1398a308"}, {file = "typing-3.10.0.0-py3-none-any.whl", hash = "sha256:12fbdfbe7d6cca1a42e485229afcb0b0c8259258cfb919b8a5e2a5c953742f89"}, @@ -2390,7 +1984,6 @@ reference = "tencent" name = "typing-extensions" version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" -category = "main" optional = false python-versions = "*" files = [ @@ -2411,7 +2004,6 @@ reference = "tencent" name = "urllib3" version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" files = [ @@ -2433,7 +2025,6 @@ reference = "tencent" name = "virtualenv" version = "20.6.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -2458,31 +2049,10 @@ type = "legacy" url = "https://mirrors.cloud.tencent.com/pypi/simple" reference = "tencent" -[[package]] -name = "wcwidth" -version = "0.2.5" -description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] - -[package.dependencies] -"backports.functools-lru-cache" = {version = ">=1.2.1", markers = "python_version < \"3.2\""} - -[package.source] -type = "legacy" -url = "https://mirrors.cloud.tencent.com/pypi/simple" -reference = "tencent" - [[package]] name = "yarl" version = "1.6.3" description = "Yet another URL library" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2539,7 +2109,6 @@ reference = "tencent" name = "yaspin" version = "2.0.0" description = "Yet Another Terminal Spinner" -category = "dev" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -2559,7 +2128,6 @@ reference = "tencent" name = "zipp" version = "1.2.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=2.7" files = [ @@ -2567,9 +2135,6 @@ files = [ {file = "zipp-1.2.0.tar.gz", hash = "sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1"}, ] -[package.dependencies] -contextlib2 = {version = "*", markers = "python_version < \"3.4\""} - [package.extras] docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] testing = ["func-timeout", "jaraco.itertools", "pathlib2", "unittest2"] @@ -2586,4 +2151,4 @@ monitor = ["prometheus-client"] [metadata] lock-version = "2.0" python-versions = "^2.7 || ^3.6" -content-hash = "a511699900912e4824cbcf81f571527eef5d4b7cb50c1cbcd6166ddffd0561d0" +content-hash = "cb0206bba0c517f668997ce4432d3078b5a305eda4646ed57db4c7e6ba18a92c" diff --git a/sdks/bkapi-client-core/pyproject.toml b/sdks/bkapi-client-core/pyproject.toml index 88405b0a..4fa30168 100644 --- a/sdks/bkapi-client-core/pyproject.toml +++ b/sdks/bkapi-client-core/pyproject.toml @@ -29,25 +29,23 @@ django=["bkoauth", "prometheus-client"] monitor=["prometheus-client"] [tool.poetry.dev-dependencies] -black = {version = "^21.6b0", python = "^3.7"} -flake8 = {version = "^3.9.2", python = "^3.7"} -isort = {version = "^5.9.1", python = "^3.7"} -mypy = {version = "^0.910", python = "^3.7"} -pre-commit = {version = "^2.13.0", python = "^3.7"} -pytest = {version = "^4.6"} -pytest-cov = {version = "^2.12.1"} -pyproject-flake8 = {version = "^0.0.1-alpha.2", python = "^3.7"} +pytest = {version = "^7.0.1", python = "^3.7"} +pytest-cov = {version = "^4.0.0", python = "^3.7"} +pytest-mock = {version = "^3.6.1", python = "^3.7"} +pytest-django = {version = "^4.5.0", python = "^3.7"} +pytest-pretty = {version = "^1.1.0", python = "~3.7.0"} +Faker = {version = "^14.2.1", python = "^3.7"} +ruff = {version = "^0.1.3", python = "~3.7.0"} +mypy = {version = "^0.971", python = "^3.7"} +pre-commit = {version = "^2.17.0", python = "^3.7"} requests-mock = {version = "^1.9.3"} dephell = {version = "^0.8.3", python = "^3.7"} tox = {version = "^3.23.1", python = "^3.7"} -pytest-mock = {version = "^2.0"} -pytest-faker = {version = "^2.0.0"} more-itertools = "^5.0" types-requests = {version = "^2.25.0", python = "^3.6"} -faker = {version = "3.0.1", python = "2.7"} +types-six = {version = "1.16.21.9", python = "^3.6"} dataclasses = {version = "0.8", python = "~3.6"} django = "1.11.20" -pytest-django = "^3.10" prometheus-client = {version = "*"} bkoauth = {version = "*", optional = true} @@ -58,48 +56,118 @@ build-backend = "poetry.core.masonry.api" [[tool.poetry.source]] name = "tencent" url = "https://mirrors.cloud.tencent.com/pypi/simple/" -default = true - -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -line_length = 119 - -[tool.black] -line-length = 119 -skip-string-normalization = 'true' -target-version = ['py27'] -exclude = ''' -/( - node_modules/.* - | .*/migrations -)/ -''' - -[tool.flake8] -ignore = "C901,F405,F403,W504,E741,E125,W503,F841,E203,E231,F541,W292" -exclude = "*migrations*,*.pyc,.git,__pycache__,venv," -max-line-length = 119 -max-complexity = 12 -format = "pylint" -show_source = "true" -statistics = "true" -count = "true" +priority = "default" [tool.mypy] ignore_missing_imports = true +follow_imports = "skip" +no_implicit_optional = true show_error_codes = true +strict_optional = true +pretty = true [[tool.mypy.overrides]] -module = "*.migrations.*" +module = [ + "*.migrations.*", +] ignore_errors = true [tool.pytest.ini_options] +addopts = "-p no:pastebin -p no:nose -p no:doctest -p no:warnings" testpaths = ["tests"] -python_files = ["tests.py", "test_*.py"] -filterwarnings = "ignore::DeprecationWarning" + +[tool.ruff] +# https://docs.astral.sh/ruff/rules/ +select = [ + "E", + "F", + "W", + "I", + "C90", + "B", + "PIE", + "C4", + "PL", + "RET", + "N", + "PERF", + "G", + "TRY", + "SIM", + "PT", +] + +# Disable E501 until this issue is fixed: https://github.com/astral-sh/ruff/issues/3825 +ignore = [ + # https://beta.ruff.rs/docs/rules/assert-raises-exception/ + "B017", + # https://beta.ruff.rs/docs/rules/raise-without-from-inside-except/ + "B904", + # https://beta.ruff.rs/docs/rules/zip-without-explicit-strict/ + "B905", + # https://beta.ruff.rs/docs/rules/line-too-long/ + "E501", + # https://beta.ruff.rs/docs/rules/ambiguous-variable-name/ + "E741", + # https://beta.ruff.rs/docs/rules/unused-variable/ + "F841", + # https://beta.ruff.rs/docs/rules/error-suffix-on-exception-name/ + "N818", + # https://beta.ruff.rs/docs/rules/try-except-in-loop/ + "PERF203", + # https://beta.ruff.rs/docs/rules/too-many-arguments/ + "PLR0913", + # https://beta.ruff.rs/docs/rules/raise-vanilla-args/ + "TRY003", + # https://beta.ruff.rs/docs/rules/reraise-no-cause/ + "TRY200", + # https://beta.ruff.rs/docs/rules/try-consider-else/ + "TRY300", + # https://beta.ruff.rs/docs/rules/raise-within-try/ + "TRY301", + # https://beta.ruff.rs/docs/rules/magic-value-comparison/ + "PLR2004", + # https://beta.ruff.rs/docs/rules/suppressible-exception/ + "SIM105", + # https://beta.ruff.rs/docs/rules/open-file-with-context-handler/ + "SIM115", +] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + "*/migrations/*", +] + +# Same as Black. +line-length = 119 + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 12 + +[tool.ruff.isort] +relative-imports-order = "closest-to-furthest" +known-first-party = ["bkapi_client_core"] [tool.tox] legacy_tox_ini = """ diff --git a/sdks/bkapi-client-core/tests/apigateway/test_client.py b/sdks/bkapi-client-core/tests/apigateway/test_client.py index 06912c8e..a4a7825f 100644 --- a/sdks/bkapi-client-core/tests/apigateway/test_client.py +++ b/sdks/bkapi-client-core/tests/apigateway/test_client.py @@ -36,7 +36,7 @@ def test_init_with_args(self, faker): assert client._endpoint == endpoint + "/{stage_name}" @pytest.mark.parametrize( - "endpoint, stage, expected", + ("endpoint", "stage", "expected"), [ (None, None, "/prod"), ("http://bkapi.example.com", None, "http://bkapi.example.com/prod"), @@ -52,7 +52,7 @@ def test_get_endpoint(self, endpoint, stage, expected): assert client._get_endpoint() == expected @pytest.mark.parametrize( - "stage, mappings, expected", + ("stage", "mappings", "expected"), [ (None, None, "prod"), (None, {}, "prod"), diff --git a/sdks/bkapi-client-core/tests/apigateway/test_django_helper.py b/sdks/bkapi-client-core/tests/apigateway/test_django_helper.py index 4b1caafb..87dab1bf 100644 --- a/sdks/bkapi-client-core/tests/apigateway/test_django_helper.py +++ b/sdks/bkapi-client-core/tests/apigateway/test_django_helper.py @@ -14,7 +14,7 @@ @pytest.mark.parametrize( - "endpoint, bk_api_url_tmpl, expected", + ("endpoint", "bk_api_url_tmpl", "expected"), [ ("http://example.com", "http://", "http://example.com"), (None, "http://{api_name}.example.com", "http://{api_name}.example.com"), diff --git a/sdks/bkapi-client-core/tests/esb/test_client.py b/sdks/bkapi-client-core/tests/esb/test_client.py index 5b99d80a..92175e03 100644 --- a/sdks/bkapi-client-core/tests/esb/test_client.py +++ b/sdks/bkapi-client-core/tests/esb/test_client.py @@ -19,7 +19,7 @@ def test_name(self): assert client.name == "esb" @pytest.mark.parametrize( - "use_test_env, expected", + ("use_test_env", "expected"), [ (True, {"X-Use-Test-Env": "true"}), (False, {}), @@ -33,7 +33,7 @@ def test_set_use_test_env(self, use_test_env, expected): assert client.session.headers == expected @pytest.mark.parametrize( - "language, expected", + ("language", "expected"), [ ("en", {"Blueking-Language": "en", "Accept-Language": "en"}), ("", {}), @@ -48,7 +48,7 @@ def test_set_language(self, language, expected): assert client.session.headers == expected @pytest.mark.parametrize( - "bk_api_ver, expected", + ("bk_api_ver", "expected"), [ ("v2", {"bk_api_ver": "/v2"}), ("", {"bk_api_ver": ""}), @@ -61,7 +61,7 @@ def test_set_bk_api_ver(self, bk_api_ver, expected): assert client.session.path_params == expected @pytest.mark.parametrize( - "headers, key, value, expected", + ("headers", "key", "value", "expected"), [ ({}, "x-color", "red", {"x-color": "red"}), ({}, "x-color", "", {"x-color": ""}), @@ -76,7 +76,7 @@ def test_set_header(self, headers, key, value, expected): assert client.session.headers == expected @pytest.mark.parametrize( - "headers, key, expected", + ("headers", "key", "expected"), [ ({"x-color": "red"}, "x-token", {"x-color": "red"}), ({"x-color": "red"}, "x-color", {}), diff --git a/sdks/bkapi-client-core/tests/esb/test_django_helper.py b/sdks/bkapi-client-core/tests/esb/test_django_helper.py index d52291c7..5d4abc6e 100644 --- a/sdks/bkapi-client-core/tests/esb/test_django_helper.py +++ b/sdks/bkapi-client-core/tests/esb/test_django_helper.py @@ -14,7 +14,7 @@ @pytest.mark.parametrize( - "endpoint, bk_component_api_url, expected", + ("endpoint", "bk_component_api_url", "expected"), [ ("http://example.com", "http://", "http://example.com"), (None, "http://bkapi.example.com", "http://bkapi.example.com"), diff --git a/sdks/bkapi-client-core/tests/test_auth.py b/sdks/bkapi-client-core/tests/test_auth.py index 70bf5f6f..b7b81e81 100644 --- a/sdks/bkapi-client-core/tests/test_auth.py +++ b/sdks/bkapi-client-core/tests/test_auth.py @@ -28,7 +28,7 @@ def test_update(self): assert auth.auth["y"] is None @pytest.mark.parametrize( - "auth, expected", + ("auth", "expected"), [ ({"x": "test", "y": None}, {"x": "test"}), ({"access_token": "test", "jwt": "test"}, {"access_token": "test", "jwt": "test"}), diff --git a/sdks/bkapi-client-core/tests/test_base.py b/sdks/bkapi-client-core/tests/test_base.py index 60b3ccd7..a105b333 100644 --- a/sdks/bkapi-client-core/tests/test_base.py +++ b/sdks/bkapi-client-core/tests/test_base.py @@ -15,7 +15,7 @@ class TestOperationResource: @pytest.fixture(autouse=True) - def setup(self, mocker): + def _setup(self, mocker): self.manager = mocker.MagicMock() self.resource = OperationResource() @@ -47,12 +47,12 @@ def test_str_without_manager(self): class TestOperation: @pytest.fixture(autouse=True) - def setup(self, mocker): + def _setup(self, mocker): self.manager = mocker.MagicMock() self.operation = Operation() def test_call_without_bind(self): - with pytest.raises(ValueError): # type: ignore + with pytest.raises(ValueError): # noqa self.operation() def test_call_with_bind(self, faker): @@ -65,7 +65,7 @@ def test_call_with_bind(self, faker): assert self.operation() is result @pytest.mark.parametrize( - "init_args,call_args,call_data,excepted", + ("init_args", "call_args", "call_data", "excepted"), [ ( {"method": "POST", "path": "/"}, @@ -103,7 +103,7 @@ def test_get_context(self, init_args, call_args, call_data, excepted, faker): class TestOperationGroup: @pytest.fixture(autouse=True) - def setup(self, mocker, faker): + def _setup(self, mocker, faker): self.manager = mocker.MagicMock() self.group = OperationGroup(name=faker.pystr(), manager=self.manager) @@ -126,16 +126,16 @@ def test_operation_already_registered(self, faker): self.group.register(name, Operation()) - with pytest.raises(ValueError): # type: ignore + with pytest.raises(ValueError): # noqa self.group.register(name, Operation()) def test_register_with_empty_name(self): - with pytest.raises(ValueError): # type: ignore + with pytest.raises(ValueError): # noqa self.group.register("", Operation()) def test_handle_without_bind(self, mocker): group = OperationGroup() - with pytest.raises(ValueError): # type: ignore + with pytest.raises(ValueError): # noqa group.get_client() def test_handle_with_bind(self, mocker, faker): @@ -155,5 +155,5 @@ def test_registered_operation(self): assert self.group.test is operation def test_non_registered_operation(self): - with pytest.raises(AttributeError): # type: ignore - self.group.test + with pytest.raises(AttributeError): + _ = self.group.test diff --git a/sdks/bkapi-client-core/tests/test_client.py b/sdks/bkapi-client-core/tests/test_client.py index 0d68254d..6b1a5d53 100644 --- a/sdks/bkapi-client-core/tests/test_client.py +++ b/sdks/bkapi-client-core/tests/test_client.py @@ -21,11 +21,11 @@ class TestRequestContextBuilder: @pytest.fixture(autouse=True) - def setup(self): + def _setup(self): self.builder = RequestContextBuilder() @pytest.mark.parametrize( - "endpoint,path,excepted", + ("endpoint", "path", "excepted"), [ ("http://example.com", "api/test", "http://example.com/api/test"), ("http://example.com", "/api/test", "http://example.com/api/test"), @@ -40,7 +40,7 @@ def test_build_url(self, endpoint, path, excepted): assert context["url"] == excepted @pytest.mark.parametrize( - "method,params,data,excepted_params,excepted_json", + ("method", "params", "data", "excepted_params", "excepted_json"), [ ( "GET", @@ -150,7 +150,7 @@ def test_build_data(self, method, params, data, excepted_params, excepted_json): assert context.get("json") == excepted_json @pytest.mark.parametrize( - "input,output", + ("input", "output"), [ ( {"endpoint": "http://example.com", "path": "/api/", "method": "GET"}, @@ -179,7 +179,7 @@ def test_build_request_context(self, input, output): class TestResponseHeadersRepresenter: @pytest.mark.parametrize( - "headers, key, default, expected", + ("headers", "key", "default", "expected"), [ (None, "test", "", ""), ({"x-color": "red"}, "x-color", "", "red"), @@ -203,7 +203,7 @@ def test_request_id(self, mocker): assert headers.request_id == "abcdef" @pytest.mark.parametrize( - "headers, expected", + ("headers", "expected"), [ ({"X-Bkapi-Error-Code": "error"}, True), ({}, False), @@ -214,7 +214,7 @@ def test_has_apigateway_error(self, headers, expected): assert headers.has_apigateway_error == expected @pytest.mark.parametrize( - "headers, expected", + ("headers", "expected"), [ ( { @@ -246,7 +246,7 @@ def test_str(self, headers, expected): class TestBaseClient: @pytest.fixture(autouse=True) - def setup(self, faker, requests_mock): + def _setup(self, faker, requests_mock): self.client = BaseClient(faker.url()) def test_client_default_name(self): @@ -284,7 +284,7 @@ def test_reuse_session_connection(self, mocker, faker, requests_mock): mock_close.assert_called_once_with() @pytest.mark.parametrize( - "endpoint,operation_path,excepted_url", + ("endpoint", "operation_path", "excepted_url"), [ ("http://example.com", "echo", "http://example.com/echo"), ("http://example.com/", "/echo", "http://example.com/echo"), @@ -373,7 +373,7 @@ def test_parse_response_error(self, mocker): self.client.parse_response(mocker.MagicMock(), mocker.MagicMock()) @pytest.mark.parametrize( - "response, expected_error", + ("response", "expected_error"), [ ( None, @@ -402,7 +402,7 @@ def test_check_response_apigateway_error(self, mocker, response, expected_error) self.client.check_response_apigateway_error(mocker.MagicMock(**response)) @pytest.mark.parametrize( - "session_headers, headers, expected", + ("session_headers", "headers", "expected"), [ ( {"x-token": "test"}, @@ -429,7 +429,7 @@ def test_update_headers(self, mocker, faker, session_headers, headers, expected) assert client.session.headers == expected @pytest.mark.parametrize( - "auth,update_auth,expected", + ("auth", "update_auth", "expected"), [ ( {}, diff --git a/sdks/bkapi-client-core/tests/test_config.py b/sdks/bkapi-client-core/tests/test_config.py index 5998da60..39ac0cbd 100644 --- a/sdks/bkapi-client-core/tests/test_config.py +++ b/sdks/bkapi-client-core/tests/test_config.py @@ -28,7 +28,7 @@ def django_settings(faker): class TestDefaultsSettings: @pytest.fixture(autouse=True) - def setup(self, env): + def _setup(self, env): self.settings = Settings() def test_set_defaults_with_position_arg(self): @@ -42,7 +42,7 @@ def test_set_defaults_with_position_arg(self): class TestEnvSettings: @pytest.fixture(autouse=True) - def setup(self, env): + def _setup(self, env): self.settings = Settings(env=env) def test_get_no_exists_in_env(self): @@ -87,7 +87,7 @@ def test_defaults(self, env): class TestDjangoSettings(TestEnvSettings): @pytest.fixture(autouse=True) - def setup(self, env, django_settings): + def _setup(self, env, django_settings): self.settings = Settings(env=env, settings=django_settings) def test_get_no_exists_in_settings(self): diff --git a/sdks/bkapi-client-core/tests/test_django_helper.py b/sdks/bkapi-client-core/tests/test_django_helper.py index 7a3b50f2..21a41488 100644 --- a/sdks/bkapi-client-core/tests/test_django_helper.py +++ b/sdks/bkapi-client-core/tests/test_django_helper.py @@ -41,7 +41,7 @@ def mock_validate_user_authenticated(mocker): @pytest.mark.parametrize( - "app_code_passed,app_secret_passed,app_code_in_settings,app_secret_in_settings", + ("app_code_passed", "app_secret_passed", "app_code_in_settings", "app_secret_in_settings"), [ (False, False, True, True), (True, True, False, False), @@ -96,7 +96,7 @@ def test_vaildate_user_authenticated_error(django_request, is_authenticated): @pytest.mark.parametrize( - "cookies, session, cookie_name_to_key, expected", + ("cookies", "session", "cookie_name_to_key", "expected"), [ ({"color": "red"}, {}, {"color": "color"}, {"color": "red"}), ({"color": "red"}, {}, {"color": "color_name"}, {"color_name": "red"}), @@ -111,7 +111,7 @@ def test_get_authorization_from_cookies(mocker, cookies, session, cookie_name_to @pytest.mark.parametrize( - "bkoauth,authorization_in_cookies,expected_access_token", + ("bkoauth", "authorization_in_cookies", "expected_access_token"), [ (None, {}, None), ({"get_access_token.return_value.access_token": "test_token"}, {}, "test_token"), @@ -157,7 +157,7 @@ def test_get_client_by_request_with_verify(verify, core_settings, client_cls, dj @pytest.mark.parametrize( - "bkoauth,expected_access_token", + ("bkoauth", "expected_access_token"), [ (None, None), ({"get_access_token_by_user.return_value.access_token": "test_token"}, "test_token"), diff --git a/sdks/bkapi-client-core/tests/test_exceptions.py b/sdks/bkapi-client-core/tests/test_exceptions.py index bc337132..be022ad4 100644 --- a/sdks/bkapi-client-core/tests/test_exceptions.py +++ b/sdks/bkapi-client-core/tests/test_exceptions.py @@ -16,7 +16,7 @@ class TestResponseError: @pytest.mark.parametrize( - "error, response, headers, expected", + ("error", "response", "headers", "expected"), [ ( "error", @@ -93,7 +93,7 @@ def test_curl_command(self, mocker, faker): assert err.curl_command == "curl -X GET http://example.com" @pytest.mark.parametrize( - "request_, expected", + ("request_", "expected"), [ (None, None), ({"method": "GET"}, "GET"), @@ -108,7 +108,7 @@ def test_request_method(self, mocker, faker, request_, expected): assert err.request_method == expected @pytest.mark.parametrize( - "request_, expected", + ("request_", "expected"), [ (None, ""), ({"url": "http://example.com/test?foo=bar"}, "http://example.com/test"), @@ -123,7 +123,7 @@ def test_request_url(self, mocker, faker, request_, expected): assert err.request_url == expected @pytest.mark.parametrize( - "response, expected", + ("response", "expected"), [ (None, None), ({"status_code": 200}, 200), diff --git a/sdks/bkapi-client-core/tests/test_prometheus.py b/sdks/bkapi-client-core/tests/test_prometheus.py index cbf7b26c..d340bb74 100644 --- a/sdks/bkapi-client-core/tests/test_prometheus.py +++ b/sdks/bkapi-client-core/tests/test_prometheus.py @@ -31,8 +31,7 @@ def mock_registry(): @pytest.fixture() def mock_operation(mocker): - operation = mocker.MagicMock() - return operation + return mocker.MagicMock() def test_enable_collector(mocker, mock_registry, mock_register_global_hook): @@ -46,7 +45,7 @@ def test_enable_collector(mocker, mock_registry, mock_register_global_hook): class TestHookCollector: @pytest.fixture(autouse=True) - def setup(self, mock_registry): + def _setup(self, mock_registry): self.collector = HookCollector( registry=mock_registry, namespace="", @@ -74,12 +73,12 @@ def test_request_hook_with_exists_hook(self, mocker): assert len(result["hooks"][HookEvent.RESPONSE]) == 2 @pytest.mark.parametrize( - "request_size, request_headers, response_size, response_headers", + ("request_size", "request_headers", "response_size", "response_headers"), [ - [0, {}, 0, {}], - [0, {"Content-Length": ""}, 0, {"Content-Length": ""}], - [123, {"Content-Length": "123"}, 456, {"Content-Length": "456"}], - [0, {"Content-Length": "NAN"}, 0, {"Content-Length": "NAN"}], + (0, {}, 0, {}), + (0, {"Content-Length": ""}, 0, {"Content-Length": ""}), + (123, {"Content-Length": "123"}, 456, {"Content-Length": "456"}), + (0, {"Content-Length": "NAN"}, 0, {"Content-Length": "NAN"}), ], ) def test_response_hook( diff --git a/sdks/bkapi-client-core/tests/test_property.py b/sdks/bkapi-client-core/tests/test_property.py index 4d966853..9917f3b4 100644 --- a/sdks/bkapi-client-core/tests/test_property.py +++ b/sdks/bkapi-client-core/tests/test_property.py @@ -60,8 +60,8 @@ class Manager(object): mock_cls.assert_not_called() # visit the attr - manager.attr - manager.attr + _ = manager.attr + _ = manager.attr mock_cls.assert_called_once_with(1, x=2) attr.bind.assert_called_once_with(mocker.ANY, manager) diff --git a/sdks/bkapi-client-core/tests/test_session.py b/sdks/bkapi-client-core/tests/test_session.py index 31bf2a5b..f68cf7ab 100644 --- a/sdks/bkapi-client-core/tests/test_session.py +++ b/sdks/bkapi-client-core/tests/test_session.py @@ -17,7 +17,7 @@ class TestSession: @pytest.fixture(autouse=True) - def setup(self, mocker): + def _setup(self, mocker): self.session = Session() def test_init(self): @@ -25,7 +25,7 @@ def test_init(self): assert session.headers["X-Testing"] == "1" @pytest.mark.parametrize( - "url, path_params, session_path_params", + ("url", "path_params", "session_path_params"), [ ("http://example.com/red/", {}, {}), ("http://example.com/{ color }/", {"color": "red"}, {}), @@ -37,7 +37,7 @@ def test_init(self): ) def test_handle(self, requests_mock, url, path_params, session_path_params): requests_mock.get("http://example.com/red/", json={"a": "b"}) - session = Session(**{"path_params": session_path_params}) + session = Session(path_params=session_path_params) result = session.handle(url, method="GET", path_params=path_params) assert result.json() == {"a": "b"} diff --git a/sdks/bkapi-client-core/tests/test_utils.py b/sdks/bkapi-client-core/tests/test_utils.py index 4c25304e..729f4b14 100644 --- a/sdks/bkapi-client-core/tests/test_utils.py +++ b/sdks/bkapi-client-core/tests/test_utils.py @@ -14,13 +14,13 @@ from bkapi_client_core import utils -@pytest.fixture +@pytest.fixture() def fake_request(): return requests.Request("GET", "https://example.com/get").prepare() @pytest.mark.parametrize( - "base_url, path, expected", + ("base_url", "path", "expected"), [ (None, "/test/", "/test/"), ("", "/test/", "/test/"), @@ -46,7 +46,7 @@ def test_to_curl(fake_request): class TestSensitiveCleaner: @pytest.mark.parametrize( - "data, expected", + ("data", "expected"), [ ( { @@ -82,7 +82,7 @@ def test_clean(self, data, expected): class TestWrappedRequest: @pytest.mark.parametrize( - "headers, expected", + ("headers", "expected"), [ ( {}, @@ -113,6 +113,6 @@ def test_str(self, fake_request): fake_request.prepare_headers({"x-token": "test", "x-bkapi-authorization": '{"bk_app_secret": "bar"}'}) result = utils.CurlRequest(fake_request).to_curl() assert result == ( - "curl -X GET -H 'X-Bkapi-Authorization: {\"bk_app_secret\": \"***\"}' " + 'curl -X GET -H \'X-Bkapi-Authorization: {"bk_app_secret": "***"}\' ' "-H 'x-token: test' 'https://example.com/get?foo=bar'" )