From e17f604909f8b204be4180fae914a2a4b2a2fdaf Mon Sep 17 00:00:00 2001 From: Jason S Fillman <6155956+jsfillman@users.noreply.github.com> Date: Mon, 28 Nov 2022 19:11:54 -0800 Subject: [PATCH 01/37] Adding manual build workflow --- .github/workflows/manual-build.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/manual-build.yml diff --git a/.github/workflows/manual-build.yml b/.github/workflows/manual-build.yml new file mode 100644 index 0000000..944f903 --- /dev/null +++ b/.github/workflows/manual-build.yml @@ -0,0 +1,11 @@ +--- +name: Manual Build & Push +on: + workflow_dispatch: +jobs: + build-push: + uses: kbase/.github/.github/workflows/reusable_build-push.yml@main + with: + name: '${{ github.event.repository.name }}-develop' + tags: br-${{ github.ref_name }} + secrets: inherit From 20318c47054c7f11d746341b0e08311f22439709 Mon Sep 17 00:00:00 2001 From: Sijie Date: Mon, 28 Apr 2025 16:27:46 -0700 Subject: [PATCH 02/37] add codeql and dependabot --- .github/codeql.yml | 52 ++++++++++++++++++++++++++++++++++++++++++ .github/dependabot.yml | 23 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 .github/codeql.yml create mode 100644 .github/dependabot.yml diff --git a/.github/codeql.yml b/.github/codeql.yml new file mode 100644 index 0000000..0f2f982 --- /dev/null +++ b/.github/codeql.yml @@ -0,0 +1,52 @@ +name: "Code scanning - action" + +on: + push: + pull_request: + schedule: + - cron: '0 19 * * 0' + +jobs: + CodeQL-Build: + + # CodeQL runs on ubuntu-latest and windows-latest + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1cadfe8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 +updates: + + # Docker + - package-ecosystem: docker + directory: "/" + schedule: + interval: "monthly" + open-pull-requests-limit: 25 + + # Python + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" + open-pull-requests-limit: 25 + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: ".github/workflows" + schedule: + interval: "monthly" + open-pull-requests-limit: 25 From d757a408625271980ecf6e7537885a64ad298399 Mon Sep 17 00:00:00 2001 From: Sijie Date: Mon, 28 Apr 2025 17:03:03 -0700 Subject: [PATCH 03/37] add standard workflows --- .github/workflows/build-test-push.yml | 69 ------------------- .github/workflows/pr_build.yml | 43 ++++++++++++ .github/workflows/release-main.yml | 25 +++++++ .../{test-pull-request.yml => test.yml} | 0 4 files changed, 68 insertions(+), 69 deletions(-) delete mode 100644 .github/workflows/build-test-push.yml create mode 100644 .github/workflows/pr_build.yml create mode 100644 .github/workflows/release-main.yml rename .github/workflows/{test-pull-request.yml => test.yml} (100%) diff --git a/.github/workflows/build-test-push.yml b/.github/workflows/build-test-push.yml deleted file mode 100644 index 2f99a3f..0000000 --- a/.github/workflows/build-test-push.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Build, Test, Push for Development Scenarios and Release - -on: - push: - branches: [ develop, "fix-*", "feature-*" ] - release: - types: [published] - -jobs: - docker_build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7] - steps: - - name: Check out GitHub Repo - uses: actions/checkout@v2 - - # Imports many useful environment variables - - uses: FranzDiebold/github-env-vars-action@v2 - - # Unit (ish) tests - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Pip installation - run: python -m pip install --upgrade pip poetry - - name: Poetry installation - run: poetry install - - name: Create test image - env: - TAG: ${{ env.CI_ACTION_REF_NAME }} - run: docker-compose build - - name: Run tests - run: scripts/run_tests - - name: Codecov - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.xml - fail_ci_if_error: true - - # Build and Push (if we get here) - - name: Get current date - id: date - run: echo "::set-output name=date::$(date -u +'%Y-%m-%dT%H:%M:%SZ')" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to GitHub Container Registry (GHCR) - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ secrets.GHCR_USERNAME }} - password: ${{ secrets.GHCR_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile - pull: true - push: true - build-args: | - BUILD_CONFIG=ci - BUILD_DATE=${{ steps.date.outputs.date }} - VCS_REF=${{ github.sha }} - BRANCH=${{ github.ref }} - TAG=${{ github.ref }} - tags: ghcr.io/${{ github.repository_owner }}/searchapi2:${{ env.CI_ACTION_REF_NAME }} diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml new file mode 100644 index 0000000..0fa1c46 --- /dev/null +++ b/.github/workflows/pr_build.yml @@ -0,0 +1,43 @@ +--- +name: Pull Request Build, Tag, & Push +on: + pull_request: + branches: + - develop + - main + - master + types: + - opened + - reopened + - synchronize + - closed +jobs: + build-develop-open: + if: github.base_ref == 'develop' && github.event.pull_request.merged == false + uses: kbase/.github/.github/workflows/reusable_build.yml@main + secrets: inherit + build-develop-merge: + if: github.base_ref == 'develop' && github.event.pull_request.merged == true + uses: kbase/.github/.github/workflows/reusable_build-push.yml@main + with: + name: '${{ github.event.repository.name }}-develop' + tags: pr-${{ github.event.number }},latest + secrets: inherit + build-main-open: + if: (github.base_ref == 'main' || github.base_ref == 'master') && github.event.pull_request.merged == false + uses: kbase/.github/.github/workflows/reusable_build-push.yml@main + with: + name: '${{ github.event.repository.name }}' + tags: pr-${{ github.event.number }} + secrets: inherit + build-main-merge: + if: (github.base_ref == 'main' || github.base_ref == 'master') && github.event.pull_request.merged == true + uses: kbase/.github/.github/workflows/reusable_build-push.yml@main + with: + name: '${{ github.event.repository.name }}' + tags: pr-${{ github.event.number }},latest-rc + secrets: inherit + trivy-scans: + if: (github.base_ref == 'develop' || github.base_ref == 'main' || github.base_ref == 'master' ) && github.event.pull_request.merged == false + uses: kbase/.github/.github/workflows/reusable_trivy-scans.yml@main + secrets: inherit diff --git a/.github/workflows/release-main.yml b/.github/workflows/release-main.yml new file mode 100644 index 0000000..a254678 --- /dev/null +++ b/.github/workflows/release-main.yml @@ -0,0 +1,25 @@ +--- +name: Release - Build & Push Image +on: + release: + branches: + - main + - master + types: [ published ] +jobs: + check-source-branch: + uses: kbase/.github/.github/workflows/reusable_validate-branch.yml@main + with: + build_branch: '${{ github.event.release.target_commitish }}' + validate-release-tag: + needs: check-source-branch + uses: kbase/.github/.github/workflows/reusable_validate-release-tag.yml@main + with: + release_tag: '${{ github.event.release.tag_name }}' + build-push: + needs: validate-release-tag + uses: kbase/.github/.github/workflows/reusable_build-push.yml@main + with: + name: '${{ github.event.repository.name }}' + tags: '${{ github.event.release.tag_name }},latest' + secrets: inherit diff --git a/.github/workflows/test-pull-request.yml b/.github/workflows/test.yml similarity index 100% rename from .github/workflows/test-pull-request.yml rename to .github/workflows/test.yml From c77e3488a8c6587533bb3ff0468695d9f338860d Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 29 Apr 2025 12:36:32 -0700 Subject: [PATCH 04/37] update test.yml file --- .github/workflows/test.yml | 39 ++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 91bb1cb..983b172 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,31 +5,46 @@ name: Run tests on: pull_request: - branches: [ "*" ] + types: + - opened + - reopened + - synchronize + - ready_for_review + push: + # run workflow when merging to main or develop + branches: + - main + - master + - develop + workflow_dispatch: jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7] + steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + - name: Check out GitHub repo + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: 3.9.19 + - name: Pip installation run: python -m pip install --upgrade pip poetry + - name: Poetry installation run: poetry install + - name: Create test image - run: docker-compose build + run: docker compose build + - name: Run tests run: scripts/run_tests - - name: Codecov - uses: codecov/codecov-action@v1 + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.xml fail_ci_if_error: true From 586e11107e3befc661fb2f03d114172f418c8696 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 10:45:43 -0700 Subject: [PATCH 05/37] update python version in pyproject.toml and update lock file --- poetry.lock | 939 ++++++++++++++++++++++++------------------------- pyproject.toml | 4 +- 2 files changed, 463 insertions(+), 480 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7de09f6..74c9a69 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,40 +1,59 @@ +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. + [[package]] name = "aiofiles" version = "0.6.0" description = "File support for asyncio." -category = "main" optional = false python-versions = "*" +groups = ["main"] +files = [ + {file = "aiofiles-0.6.0-py3-none-any.whl", hash = "sha256:bd3019af67f83b739f8e4053c6c0512a7f545b9a8d91aaeab55e6e0f9d123c27"}, + {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, +] [[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.*" +groups = ["dev"] +markers = "sys_platform == \"win32\"" +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 = "20.3.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "dev"] +files = [ + {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, + {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, +] [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pympler", "pytest (>=4.3.0)", "six", "sphinx", "zope.interface"] docs = ["furo", "sphinx", "zope.interface"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests-no-zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] name = "bandit" version = "1.7.0" description = "Security oriented static analyser for python code." -category = "dev" optional = false python-versions = ">=3.5" +groups = ["dev"] +files = [ + {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, + {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, +] [package.dependencies] colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} @@ -47,33 +66,100 @@ stevedore = ">=1.20.0" name = "certifi" version = "2020.12.5" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = "*" +groups = ["main", "dev"] +files = [ + {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, + {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, +] [[package]] 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.*" +groups = ["main", "dev"] +files = [ + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, +] [[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.*" +groups = ["dev"] +markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" +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 = "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" +groups = ["dev"] +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.extras] toml = ["toml"] @@ -82,12 +168,15 @@ toml = ["toml"] name = "flake8" version = "3.8.4" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["dev"] +files = [ + {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, + {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, +] [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.6.0a1,<2.7.0" pyflakes = ">=2.2.0,<2.3.0" @@ -96,9 +185,13 @@ pyflakes = ">=2.2.0,<2.3.0" name = "gitdb" version = "4.0.5" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.4" +groups = ["dev"] +files = [ + {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, + {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, +] [package.dependencies] smmap = ">=3.0.1,<4" @@ -107,9 +200,13 @@ smmap = ">=3.0.1,<4" name = "gitpython" version = "3.1.14" description = "Python Git Library" -category = "dev" optional = false python-versions = ">=3.4" +groups = ["dev"] +files = [ + {file = "GitPython-3.1.14-py3-none-any.whl", hash = "sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b"}, + {file = "GitPython-3.1.14.tar.gz", hash = "sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"}, +] [package.dependencies] gitdb = ">=4.0.1,<5" @@ -118,32 +215,54 @@ gitdb = ">=4.0.1,<5" name = "h11" version = "0.9.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = "*" +groups = ["main"] +files = [ + {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, + {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, +] [[package]] name = "httpcore" version = "0.11.1" description = "A minimal low-level HTTP client." -category = "main" optional = false python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "httpcore-0.11.1-py3-none-any.whl", hash = "sha256:72cfaa461dbdc262943ff4c9abf5b195391a03cdcc152e636adb4239b15e77e1"}, + {file = "httpcore-0.11.1.tar.gz", hash = "sha256:a35dddd1f4cc34ff37788337ef507c0ad0276241ece6daf663ac9e77c0b87232"}, +] [package.dependencies] h11 = ">=0.8,<0.10" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] -http2 = ["h2 (>=3.0.0,<4.0.0)"] +http2 = ["h2 (==3.*)"] [[package]] name = "httptools" version = "0.1.1" description = "A collection of framework independent HTTP protocol utils." -category = "main" optional = false python-versions = "*" +groups = ["main"] +files = [ + {file = "httptools-0.1.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce"}, + {file = "httptools-0.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4"}, + {file = "httptools-0.1.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6"}, + {file = "httptools-0.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c"}, + {file = "httptools-0.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a"}, + {file = "httptools-0.1.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f"}, + {file = "httptools-0.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2"}, + {file = "httptools-0.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009"}, + {file = "httptools-0.1.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"}, + {file = "httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d"}, + {file = "httptools-0.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be"}, + {file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"}, +] [package.extras] test = ["Cython (==0.29.14)"] @@ -152,77 +271,78 @@ test = ["Cython (==0.29.14)"] name = "httpx" version = "0.15.4" description = "The next generation HTTP client." -category = "main" optional = false python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "httpx-0.15.4-py3-none-any.whl", hash = "sha256:7b3c07bfdcdadd92020dd4c07b15932abdcf1c898422a4e98de3d19b2223310b"}, + {file = "httpx-0.15.4.tar.gz", hash = "sha256:4c81dbf98a29cb4f51f415140df56542f9d4860798d713e336642e953cddd1db"}, +] [package.dependencies] certifi = "*" -httpcore = ">=0.11.0,<0.12.0" +httpcore = "==0.11.*" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -brotli = ["brotlipy (>=0.7.0,<0.8.0)"] -http2 = ["h2 (>=3.0.0,<4.0.0)"] +brotli = ["brotlipy (==0.7.*)"] +http2 = ["h2 (==3.*)"] [[package]] 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.*" - -[[package]] -name = "importlib-metadata" -version = "3.7.2" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +groups = ["main", "dev"] +files = [ + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, +] [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = "*" +groups = ["dev"] +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 = "jsonschema" version = "3.2.0" description = "An implementation of JSON Schema validation for Python" -category = "main" optional = false python-versions = "*" +groups = ["main"] +files = [ + {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, + {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, +] [package.dependencies] attrs = ">=17.4.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} pyrsistent = ">=0.14.0" +setuptools = "*" six = ">=1.11.0" [package.extras] format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] -format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] +format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"] [[package]] name = "kbase-jsonrpc11base" version = "0.1.6" description = "Simple JSON-RPC 1.1 service without transport layer" -category = "main" optional = false python-versions = "^3.7" +groups = ["main"] +files = [] develop = false [package.dependencies] @@ -239,9 +359,13 @@ resolved_reference = "5d59ca6b1e1e0f09ec0faab922380e9ce53014d9" name = "kbase-jsonrpcbase" version = "0.3.0a6" description = "Simple JSON-RPC service without transport layer" -category = "main" optional = false python-versions = ">=3.6,<4.0" +groups = ["main"] +files = [ + {file = "kbase_jsonrpcbase-0.3.0a6-py3-none-any.whl", hash = "sha256:775e1f8dbc157521c528a1b0bfa63cdae733dc3e8dcf743654c175ebb24bb6df"}, + {file = "kbase_jsonrpcbase-0.3.0a6.tar.gz", hash = "sha256:ad17753b3ff8bcaf2f686495387a4ff8c7d3bc2f268ce5a83afec48d1d57e690"}, +] [package.dependencies] jsonschema = ">=3.2.0,<4.0.0" @@ -251,25 +375,92 @@ pyyaml = ">=5.3.1,<6.0.0" name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" +groups = ["dev"] +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]] name = "multidict" version = "5.1.0" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da"}, + {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224"}, + {file = "multidict-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26"}, + {file = "multidict-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6"}, + {file = "multidict-5.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9"}, + {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37"}, + {file = "multidict-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5"}, + {file = "multidict-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632"}, + {file = "multidict-5.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a"}, + {file = "multidict-5.1.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea"}, + {file = "multidict-5.1.0-cp38-cp38-win32.whl", hash = "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656"}, + {file = "multidict-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3"}, + {file = "multidict-5.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841"}, + {file = "multidict-5.1.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda"}, + {file = "multidict-5.1.0-cp39-cp39-win32.whl", hash = "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"}, + {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, + {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, +] [[package]] name = "mypy" version = "0.812" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.5" +groups = ["dev"] +files = [ + {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"}, +] [package.dependencies] mypy-extensions = ">=0.4.3,<0.5.0" @@ -283,17 +474,25 @@ dmypy = ["psutil (>=4.0)"] 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 = "*" +groups = ["dev"] +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 = "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.*" +groups = ["dev"] +files = [ + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, +] [package.dependencies] pyparsing = ">=2.0.2" @@ -302,20 +501,25 @@ pyparsing = ">=2.0.2" name = "pbr" version = "5.5.1" description = "Python Build Reasonableness" -category = "dev" optional = false python-versions = ">=2.6" +groups = ["dev"] +files = [ + {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"}, + {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"}, +] [[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.*" - -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +groups = ["dev"] +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.extras] dev = ["pre-commit", "tox"] @@ -324,55 +528,77 @@ dev = ["pre-commit", "tox"] 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.*" +groups = ["dev"] +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 = "pycodestyle" version = "2.6.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["dev"] +files = [ + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, +] [[package]] name = "pyflakes" version = "2.2.0" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["dev"] +files = [ + {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, + {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, +] [[package]] name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] +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 = "pyrsistent" version = "0.17.3" description = "Persistent/Functional/Immutable data structures" -category = "main" optional = false python-versions = ">=3.5" +groups = ["main"] +files = [ + {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, +] [[package]] name = "pytest" version = "6.2.2" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, + {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, +] [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<1.0.0a1" @@ -386,50 +612,93 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm name = "pytest-cov" version = "2.11.1" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["dev"] +files = [ + {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"}, + {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"}, +] [package.dependencies] coverage = ">=5.2.1" pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests (==2.0.2)", "pytest-xdist", "six", "virtualenv"] [[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.*" +groups = ["main", "dev"] +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 = "requests" version = "2.25.1" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.dependencies] +groups = ["main", "dev"] +files = [ + {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, + {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, +] + +[package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<5" idna = ">=2.5,<3" urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +security = ["cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton ; sys_platform == \"win32\" and python_version == \"2.7\""] [[package]] name = "responses" version = "0.12.1" description = "A utility library for mocking out the `requests` Python library." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["dev"] +files = [ + {file = "responses-0.12.1-py2.py3-none-any.whl", hash = "sha256:ef265bd3200bdef5ec17912fc64a23570ba23597fd54ca75c18650fa1699213d"}, + {file = "responses-0.12.1.tar.gz", hash = "sha256:2e5764325c6b624e42b428688f2111fea166af46623cb0127c05f6afb14d3457"}, +] [package.dependencies] requests = ">=2.0" @@ -437,15 +706,19 @@ six = "*" urllib3 = ">=1.25.10" [package.extras] -tests = ["coverage (>=3.7.1,<6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "pytest (>=4.6,<5.0)", "pytest (>=4.6)"] +tests = ["coverage (>=3.7.1,<6.0.0)", "flake8", "pytest (>=4.6) ; python_version >= \"3.5\"", "pytest (>=4.6,<5.0) ; python_version < \"3.5\"", "pytest-cov", "pytest-localserver"] [[package]] name = "rfc3986" version = "1.4.0" description = "Validating URI References per RFC 3986" -category = "main" optional = false python-versions = "*" +groups = ["main"] +files = [ + {file = "rfc3986-1.4.0-py2.py3-none-any.whl", hash = "sha256:af9147e9aceda37c91a05f4deb128d4b4b49d6b199775fd2d2927768abdc8f50"}, + {file = "rfc3986-1.4.0.tar.gz", hash = "sha256:112398da31a3344dc25dbf477d8df6cb34f9278a94fee2625d89e4514be8bb9d"}, +] [package.dependencies] idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} @@ -457,9 +730,13 @@ idna2008 = ["idna"] name = "sanic" version = "20.12.2" description = "A web server and web framework that's written to go fast. Build fast. Run fast." -category = "main" optional = false python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "sanic-20.12.2-py3-none-any.whl", hash = "sha256:9f01a3ebfe4bf6c57e164bfa1b66c977cb47421e54ae91cc04173cfc711891ce"}, + {file = "sanic-20.12.2.tar.gz", hash = "sha256:b9d7e24cd293c126f6f4aaf26fcc3b11e35338b86e8c2693b71d05196e7b02b0"}, +] [package.dependencies] aiofiles = ">=0.6.0" @@ -471,445 +748,103 @@ uvloop = {version = ">=0.5.3,<0.15.0", markers = "sys_platform != \"win32\" and websockets = ">=8.1,<9.0" [package.extras] -all = ["pytest (==5.2.1)", "multidict (>=5.0,<6.0)", "gunicorn (==20.0.4)", "pytest-cov", "httpcore (>=0.11.0,<0.12.0)", "beautifulsoup4", "pytest-sanic", "pytest-sugar", "pytest-benchmark", "pytest-dependency", "aiofiles", "tox", "black", "flake8", "bandit", "towncrier", "sphinx (>=2.1.2)", "sphinx-rtd-theme", "recommonmark (>=0.5.0)", "docutils", "pygments", "uvloop (>=0.5.3,<0.15.0)", "ujson (>=1.35)"] -dev = ["pytest (==5.2.1)", "multidict (>=5.0,<6.0)", "gunicorn (==20.0.4)", "pytest-cov", "httpcore (>=0.11.0,<0.12.0)", "beautifulsoup4", "pytest-sanic", "pytest-sugar", "pytest-benchmark", "pytest-dependency", "aiofiles", "tox", "black", "flake8", "bandit", "towncrier", "uvloop (>=0.5.3,<0.15.0)", "ujson (>=1.35)"] -docs = ["sphinx (>=2.1.2)", "sphinx-rtd-theme", "recommonmark (>=0.5.0)", "docutils", "pygments"] -test = ["pytest (==5.2.1)", "multidict (>=5.0,<6.0)", "gunicorn (==20.0.4)", "pytest-cov", "httpcore (>=0.11.0,<0.12.0)", "beautifulsoup4", "pytest-sanic", "pytest-sugar", "pytest-benchmark", "pytest-dependency", "uvloop (>=0.5.3,<0.15.0)", "ujson (>=1.35)"] +all = ["aiofiles", "bandit", "beautifulsoup4", "black", "docutils", "flake8", "gunicorn (==20.0.4)", "httpcore (==0.11.*)", "multidict (>=5.0,<6.0)", "pygments", "pytest (==5.2.1)", "pytest-benchmark", "pytest-cov", "pytest-dependency", "pytest-sanic", "pytest-sugar", "recommonmark (>=0.5.0)", "sphinx (>=2.1.2)", "sphinx-rtd-theme", "towncrier", "tox", "ujson (>=1.35) ; sys_platform != \"win32\" and implementation_name == \"cpython\"", "uvloop (>=0.5.3,<0.15.0) ; sys_platform != \"win32\" and implementation_name == \"cpython\""] +dev = ["aiofiles", "bandit", "beautifulsoup4", "black", "flake8", "gunicorn (==20.0.4)", "httpcore (==0.11.*)", "multidict (>=5.0,<6.0)", "pytest (==5.2.1)", "pytest-benchmark", "pytest-cov", "pytest-dependency", "pytest-sanic", "pytest-sugar", "towncrier", "tox", "ujson (>=1.35) ; sys_platform != \"win32\" and implementation_name == \"cpython\"", "uvloop (>=0.5.3,<0.15.0) ; sys_platform != \"win32\" and implementation_name == \"cpython\""] +docs = ["docutils", "pygments", "recommonmark (>=0.5.0)", "sphinx (>=2.1.2)", "sphinx-rtd-theme"] +test = ["beautifulsoup4", "gunicorn (==20.0.4)", "httpcore (==0.11.*)", "multidict (>=5.0,<6.0)", "pytest (==5.2.1)", "pytest-benchmark", "pytest-cov", "pytest-dependency", "pytest-sanic", "pytest-sugar", "ujson (>=1.35) ; sys_platform != \"win32\" and implementation_name == \"cpython\"", "uvloop (>=0.5.3,<0.15.0) ; sys_platform != \"win32\" and implementation_name == \"cpython\""] + +[[package]] +name = "setuptools" +version = "80.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "setuptools-80.1.0-py3-none-any.whl", hash = "sha256:ea0e7655c05b74819f82e76e11a85b31779fee7c4969e82f72bab0664e8317e4"}, + {file = "setuptools-80.1.0.tar.gz", hash = "sha256:2e308396e1d83de287ada2c2fd6e64286008fe6aca5008e0b6a8cb0e2c86eedd"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "six" version = "1.15.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main", "dev"] +files = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] [[package]] name = "smmap" version = "3.0.5" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["dev"] +files = [ + {file = "smmap-3.0.5-py2.py3-none-any.whl", hash = "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714"}, + {file = "smmap-3.0.5.tar.gz", hash = "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"}, +] [[package]] name = "sniffio" version = "1.2.0" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.5" +groups = ["main"] +files = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] [[package]] name = "stevedore" version = "3.3.0" description = "Manage dynamic plugins for Python applications" -category = "dev" optional = false python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "stevedore-3.3.0-py3-none-any.whl", hash = "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"}, + {file = "stevedore-3.3.0.tar.gz", hash = "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee"}, +] [package.dependencies] -importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[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.*" +groups = ["dev"] +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 = "typed-ast" version = "1.4.2" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "typing-extensions" -version = "3.7.4.3" -description = "Backported and Experimental Type Hints for Python 3.5+" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "ujson" -version = "4.0.2" -description = "Ultra fast JSON encoder and decoder for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "urllib3" -version = "1.26.3" -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" - -[package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "uvloop" -version = "0.14.0" -description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" optional = false python-versions = "*" - -[[package]] -name = "websockets" -version = "8.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" -optional = false -python-versions = ">=3.6.1" - -[[package]] -name = "zipp" -version = "3.4.1" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.7" -content-hash = "ceca37a35537ab53e3e25016eb6b3433a42175801695d94088406151d28641b5" - -[metadata.files] -aiofiles = [ - {file = "aiofiles-0.6.0-py3-none-any.whl", hash = "sha256:bd3019af67f83b739f8e4053c6c0512a7f545b9a8d91aaeab55e6e0f9d123c27"}, - {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, -] -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-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, - {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, -] -bandit = [ - {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, - {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, -] -certifi = [ - {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, - {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, -] -chardet = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, -] -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 = [ - {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"}, -] -flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, -] -gitdb = [ - {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, - {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, -] -gitpython = [ - {file = "GitPython-3.1.14-py3-none-any.whl", hash = "sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b"}, - {file = "GitPython-3.1.14.tar.gz", hash = "sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"}, -] -h11 = [ - {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, - {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, -] -httpcore = [ - {file = "httpcore-0.11.1-py3-none-any.whl", hash = "sha256:72cfaa461dbdc262943ff4c9abf5b195391a03cdcc152e636adb4239b15e77e1"}, - {file = "httpcore-0.11.1.tar.gz", hash = "sha256:a35dddd1f4cc34ff37788337ef507c0ad0276241ece6daf663ac9e77c0b87232"}, -] -httptools = [ - {file = "httptools-0.1.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce"}, - {file = "httptools-0.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4"}, - {file = "httptools-0.1.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6"}, - {file = "httptools-0.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c"}, - {file = "httptools-0.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a"}, - {file = "httptools-0.1.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f"}, - {file = "httptools-0.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2"}, - {file = "httptools-0.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009"}, - {file = "httptools-0.1.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"}, - {file = "httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d"}, - {file = "httptools-0.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be"}, - {file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"}, -] -httpx = [ - {file = "httpx-0.15.4-py3-none-any.whl", hash = "sha256:7b3c07bfdcdadd92020dd4c07b15932abdcf1c898422a4e98de3d19b2223310b"}, - {file = "httpx-0.15.4.tar.gz", hash = "sha256:4c81dbf98a29cb4f51f415140df56542f9d4860798d713e336642e953cddd1db"}, -] -idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, -] -importlib-metadata = [ - {file = "importlib_metadata-3.7.2-py3-none-any.whl", hash = "sha256:407d13f55dc6f2a844e62325d18ad7019a436c4bfcaee34cda35f2be6e7c3e34"}, - {file = "importlib_metadata-3.7.2.tar.gz", hash = "sha256:18d5ff601069f98d5d605b6a4b50c18a34811d655c55548adc833e687289acde"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -jsonschema = [ - {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, - {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, -] -kbase-jsonrpc11base = [] -kbase-jsonrpcbase = [ - {file = "kbase_jsonrpcbase-0.3.0a6-py3-none-any.whl", hash = "sha256:775e1f8dbc157521c528a1b0bfa63cdae733dc3e8dcf743654c175ebb24bb6df"}, - {file = "kbase_jsonrpcbase-0.3.0a6.tar.gz", hash = "sha256:ad17753b3ff8bcaf2f686495387a4ff8c7d3bc2f268ce5a83afec48d1d57e690"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -multidict = [ - {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224"}, - {file = "multidict-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26"}, - {file = "multidict-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6"}, - {file = "multidict-5.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37"}, - {file = "multidict-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5"}, - {file = "multidict-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632"}, - {file = "multidict-5.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea"}, - {file = "multidict-5.1.0-cp38-cp38-win32.whl", hash = "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656"}, - {file = "multidict-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3"}, - {file = "multidict-5.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda"}, - {file = "multidict-5.1.0-cp39-cp39-win32.whl", hash = "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"}, - {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, - {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, -] -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"}, -] -packaging = [ - {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, - {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, -] -pbr = [ - {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"}, - {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"}, -] -pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, -] -py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, -] -pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, -] -pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, -] -pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, -] -pyrsistent = [ - {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, -] -pytest = [ - {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, - {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, -] -pytest-cov = [ - {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"}, - {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"}, -] -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"}, -] -requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, -] -responses = [ - {file = "responses-0.12.1-py2.py3-none-any.whl", hash = "sha256:ef265bd3200bdef5ec17912fc64a23570ba23597fd54ca75c18650fa1699213d"}, - {file = "responses-0.12.1.tar.gz", hash = "sha256:2e5764325c6b624e42b428688f2111fea166af46623cb0127c05f6afb14d3457"}, -] -rfc3986 = [ - {file = "rfc3986-1.4.0-py2.py3-none-any.whl", hash = "sha256:af9147e9aceda37c91a05f4deb128d4b4b49d6b199775fd2d2927768abdc8f50"}, - {file = "rfc3986-1.4.0.tar.gz", hash = "sha256:112398da31a3344dc25dbf477d8df6cb34f9278a94fee2625d89e4514be8bb9d"}, -] -sanic = [ - {file = "sanic-20.12.2-py3-none-any.whl", hash = "sha256:9f01a3ebfe4bf6c57e164bfa1b66c977cb47421e54ae91cc04173cfc711891ce"}, - {file = "sanic-20.12.2.tar.gz", hash = "sha256:b9d7e24cd293c126f6f4aaf26fcc3b11e35338b86e8c2693b71d05196e7b02b0"}, -] -six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, -] -smmap = [ - {file = "smmap-3.0.5-py2.py3-none-any.whl", hash = "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714"}, - {file = "smmap-3.0.5.tar.gz", hash = "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"}, -] -sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, -] -stevedore = [ - {file = "stevedore-3.3.0-py3-none-any.whl", hash = "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"}, - {file = "stevedore-3.3.0.tar.gz", hash = "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -typed-ast = [ +groups = ["dev"] +files = [ {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, @@ -941,12 +876,29 @@ typed-ast = [ {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, ] -typing-extensions = [ + +[[package]] +name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] -ujson = [ + +[[package]] +name = "ujson" +version = "4.0.2" +description = "Ultra fast JSON encoder and decoder for Python" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "sys_platform != \"win32\" and implementation_name == \"cpython\"" +files = [ {file = "ujson-4.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:e390df0dcc7897ffb98e17eae1f4c442c39c91814c298ad84d935a3c5c7a32fa"}, {file = "ujson-4.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:84b1dca0d53b0a8d58835f72ea2894e4d6cf7a5dd8f520ab4cbd698c81e49737"}, {file = "ujson-4.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:91396a585ba51f84dc71c8da60cdc86de6b60ba0272c389b6482020a1fac9394"}, @@ -969,11 +921,33 @@ ujson = [ {file = "ujson-4.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:aad6d92f4d71e37ea70e966500f1951ecd065edca3a70d3861b37b176dd6702c"}, {file = "ujson-4.0.2.tar.gz", hash = "sha256:c615a9e9e378a7383b756b7e7a73c38b22aeb8967a8bfbffd4741f7ffd043c4d"}, ] -urllib3 = [ + +[[package]] +name = "urllib3" +version = "1.26.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +groups = ["main", "dev"] +files = [ {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, ] -uvloop = [ + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "uvloop" +version = "0.14.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = "*" +groups = ["main"] +markers = "sys_platform != \"win32\" and implementation_name == \"cpython\"" +files = [ {file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"}, {file = "uvloop-0.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726"}, {file = "uvloop-0.14.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7"}, @@ -984,7 +958,15 @@ uvloop = [ {file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"}, {file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"}, ] -websockets = [ + +[[package]] +name = "websockets" +version = "8.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.6.1" +groups = ["main"] +files = [ {file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"}, {file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"}, {file = "websockets-8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8"}, @@ -1008,7 +990,8 @@ websockets = [ {file = "websockets-8.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"}, {file = "websockets-8.1.tar.gz", hash = "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f"}, ] -zipp = [ - {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, - {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, -] + +[metadata] +lock-version = "2.1" +python-versions = "3.9.19" +content-hash = "0c5bae84c928557683339e282baadc8d17847c881703ad5b1cec2494289cef4a" diff --git a/pyproject.toml b/pyproject.toml index ed3dbd2..59ee25f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = ["Your Name "] license = "MIT" [tool.poetry.dependencies] -python = "^3.7" +python = "3.9.19" sanic = "20.12.2" requests = "2.25.1" jsonschema = "3.2.0" @@ -15,7 +15,7 @@ kbase-jsonrpcbase = "0.3.0a6" kbase-jsonrpc11base = {git="https://github.com/kbaseIncubator/kbase-jsonrpc11base", branch="v0.1.6"} -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] mypy = "0.812" bandit = "1.7.0" mccabe = "0.6.1" From cb38726fd38f7b9ddf586c64e8524d350ba2bda1 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 10:48:59 -0700 Subject: [PATCH 06/37] add --no-root flag to fix package issue --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 983b172..571398d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: run: python -m pip install --upgrade pip poetry - name: Poetry installation - run: poetry install + run: poetry install --no-root - name: Create test image run: docker compose build From 4c7540e369bd2a0b369cc5e161633b007bea280c Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 11:06:30 -0700 Subject: [PATCH 07/37] update dockerfile --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b0b6dcb..b5a12ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7-alpine +FROM python:3.9.19-alpine # Dockerize related args ARG BUILD_DATE @@ -27,9 +27,9 @@ WORKDIR /app # Install dependencies COPY pyproject.toml poetry.lock /app/ RUN apk --update add --no-cache --virtual build-dependencies libffi-dev libressl-dev musl-dev python3-dev build-base git rust cargo && \ - pip install --upgrade pip poetry==1.0.9 && \ + pip install --upgrade pip poetry==2.1.2 && \ poetry config virtualenvs.create false && \ - poetry install --no-dev --no-interaction --no-ansi && \ + poetry install --no-root --without dev --no-interaction --no-ansi && \ apk del --no-cache build-dependencies COPY . /app From 860cede8a6775184d71c5ad8c0cf2d0b655444b5 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 12:45:04 -0700 Subject: [PATCH 08/37] fix docker build error --- poetry.lock | 136 ++++++++++++++++++++++++------------------------- pyproject.toml | 5 +- 2 files changed, 70 insertions(+), 71 deletions(-) diff --git a/poetry.lock b/poetry.lock index 74c9a69..464b915 100644 --- a/poetry.lock +++ b/poetry.lock @@ -313,6 +313,20 @@ files = [ {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +[[package]] +name = "jsonrpcbase" +version = "0.2.0" +description = "Simple JSON-RPC service without transport layer" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "JSONRPCBase-0.2.0.tar.gz", hash = "sha256:7ea67fc1a7c87756e9a876e18a342e431e80d0ef3ba867dfd6f3fac5bf3fcc0d"}, +] + +[package.dependencies] +six = "*" + [[package]] name = "jsonschema" version = "3.2.0" @@ -335,42 +349,6 @@ six = ">=1.11.0" format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"] -[[package]] -name = "kbase-jsonrpc11base" -version = "0.1.6" -description = "Simple JSON-RPC 1.1 service without transport layer" -optional = false -python-versions = "^3.7" -groups = ["main"] -files = [] -develop = false - -[package.dependencies] -jsonschema = "3.2.0" -pyyaml = "5.4.1" - -[package.source] -type = "git" -url = "https://github.com/kbaseIncubator/kbase-jsonrpc11base" -reference = "v0.1.6" -resolved_reference = "5d59ca6b1e1e0f09ec0faab922380e9ce53014d9" - -[[package]] -name = "kbase-jsonrpcbase" -version = "0.3.0a6" -description = "Simple JSON-RPC service without transport layer" -optional = false -python-versions = ">=3.6,<4.0" -groups = ["main"] -files = [ - {file = "kbase_jsonrpcbase-0.3.0a6-py3-none-any.whl", hash = "sha256:775e1f8dbc157521c528a1b0bfa63cdae733dc3e8dcf743654c175ebb24bb6df"}, - {file = "kbase_jsonrpcbase-0.3.0a6.tar.gz", hash = "sha256:ad17753b3ff8bcaf2f686495387a4ff8c7d3bc2f268ce5a83afec48d1d57e690"}, -] - -[package.dependencies] -jsonschema = ">=3.2.0,<4.0.0" -pyyaml = ">=5.3.1,<6.0.0" - [[package]] name = "mccabe" version = "0.6.1" @@ -629,41 +607,63 @@ testing = ["fields", "hunter", "process-tests (==2.0.2)", "pytest-xdist", "six", [[package]] name = "pyyaml" -version = "5.4.1" +version = "6.0.1" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.6" groups = ["main", "dev"] 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"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] @@ -994,4 +994,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "3.9.19" -content-hash = "0c5bae84c928557683339e282baadc8d17847c881703ad5b1cec2494289cef4a" +content-hash = "1d1d76c95ec1723eab1ac9e329a0db3d9efa807cd2b3dbfe1a2029298660e4f4" diff --git a/pyproject.toml b/pyproject.toml index 59ee25f..0b30c44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,9 +10,8 @@ python = "3.9.19" sanic = "20.12.2" requests = "2.25.1" jsonschema = "3.2.0" -pyyaml = "5.4.1" -kbase-jsonrpcbase = "0.3.0a6" -kbase-jsonrpc11base = {git="https://github.com/kbaseIncubator/kbase-jsonrpc11base", branch="v0.1.6"} +pyyaml = "6.0.1" +jsonrpcbase = "0.2.0" [tool.poetry.group.dev.dependencies] From 60c19dfce43c5732fce4d17712a2f12d352c313f Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 13:06:28 -0700 Subject: [PATCH 09/37] switch back to jsonrpcbase --- src/search1_conversion/convert_params.py | 2 +- src/search1_rpc/errors.py | 28 ++++++++++++++++++- src/search1_rpc/service.py | 4 +-- src/search1_rpc/service_description.py | 20 +++++++++++++ .../test_search1_convert_params.py | 2 +- 5 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/search1_rpc/service_description.py diff --git a/src/search1_conversion/convert_params.py b/src/search1_conversion/convert_params.py index 40e62ba..c9b6d16 100644 --- a/src/search1_conversion/convert_params.py +++ b/src/search1_conversion/convert_params.py @@ -35,7 +35,7 @@ """ from src.utils.obj_utils import get_any -from jsonrpc11base.errors import InvalidParamsError +from jsonrpcbase import InvalidParamsError # Mapping of special sorting properties names from the Java API to search2 key names _SORT_PROP_MAPPING = { diff --git a/src/search1_rpc/errors.py b/src/search1_rpc/errors.py index 1e9ecf3..e918181 100644 --- a/src/search1_rpc/errors.py +++ b/src/search1_rpc/errors.py @@ -1,7 +1,33 @@ -from jsonrpc11base.errors import APIError +from typing import Optional from src import exceptions +class APIError(Exception): + """ + APIError class based on the JSON-RPC 1.1 specs. + Should not be used directly, but subclassed. + + code - number + message - string + error - object + """ + code: int = 1 + message: str = 'API error' + error: Optional[dict] = None + + def to_json(self): + """Return the Exception data in a format for JSON-RPC.""" + + error = {'name': 'APIError', + 'code': self.code, + 'message': self.message} + + if self.error is not None: + error['error'] = self.error + + return error + + class UnknownTypeError(APIError): code = 1000 message = 'Unknown type' diff --git a/src/search1_rpc/service.py b/src/search1_rpc/service.py index 2abdf27..2123bc1 100644 --- a/src/search1_rpc/service.py +++ b/src/search1_rpc/service.py @@ -19,8 +19,8 @@ import time import os -from jsonrpc11base import JSONRPCService -from jsonrpc11base.service_description import ServiceDescription +from jsonrpcbase import JSONRPCService +from src.search1_rpc.service_description import ServiceDescription from src.es_client.query import search from src.search1_conversion import convert_params, convert_result from src.utils.logger import logger diff --git a/src/search1_rpc/service_description.py b/src/search1_rpc/service_description.py new file mode 100644 index 0000000..c61eef9 --- /dev/null +++ b/src/search1_rpc/service_description.py @@ -0,0 +1,20 @@ +class ServiceDescription(object): + def __init__(self, name, id, version=None, summary=None): + self.name = name + self.id = id + self.version = version + self.summary = summary + + def to_json(self): + data = { + 'sdversion': '1.0', + 'name': self.name, + 'id': self.id + } + if (self.version is not None): + data['version'] = self.version + + if (self.summary is not None): + data['summary'] = self.summary + + return data diff --git a/tests/unit/search1_conversion/test_search1_convert_params.py b/tests/unit/search1_conversion/test_search1_convert_params.py index 0142b7b..7f8b15a 100644 --- a/tests/unit/search1_conversion/test_search1_convert_params.py +++ b/tests/unit/search1_conversion/test_search1_convert_params.py @@ -1,7 +1,7 @@ import pytest from src.search1_conversion import convert_params -from jsonrpc11base.errors import InvalidParamsError +from jsonrpcbase import InvalidParamsError def test_search_objects_valid(): From 268545f91e05765a3f4aed8bee871e48c060f222 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 14:38:17 -0700 Subject: [PATCH 10/37] copy jsonrpc11base over --- jsonrpc11base/__init__.py | 6 + jsonrpc11base/errors.py | 233 +++++++++++++ jsonrpc11base/exceptions.py | 32 ++ jsonrpc11base/jsonrpc_schema/jsonrpc11.json | 153 +++++++++ jsonrpc11base/jsonrpc_schema/request.json | 6 + jsonrpc11base/jsonrpc_schema/response.json | 13 + jsonrpc11base/main.py | 323 ++++++++++++++++++ jsonrpc11base/method.py | 32 ++ jsonrpc11base/service_description.py | 20 ++ .../system_schema/system.describe.params.json | 0 .../system_schema/system.describe.result.json | 6 + jsonrpc11base/types.py | 16 + jsonrpc11base/validation/schema.py | 81 +++++ jsonrpc11base/validation/validation.py | 67 ++++ 14 files changed, 988 insertions(+) create mode 100644 jsonrpc11base/__init__.py create mode 100644 jsonrpc11base/errors.py create mode 100644 jsonrpc11base/exceptions.py create mode 100644 jsonrpc11base/jsonrpc_schema/jsonrpc11.json create mode 100644 jsonrpc11base/jsonrpc_schema/request.json create mode 100644 jsonrpc11base/jsonrpc_schema/response.json create mode 100644 jsonrpc11base/main.py create mode 100644 jsonrpc11base/method.py create mode 100644 jsonrpc11base/service_description.py create mode 100644 jsonrpc11base/system_schema/system.describe.params.json create mode 100644 jsonrpc11base/system_schema/system.describe.result.json create mode 100644 jsonrpc11base/types.py create mode 100644 jsonrpc11base/validation/schema.py create mode 100644 jsonrpc11base/validation/validation.py diff --git a/jsonrpc11base/__init__.py b/jsonrpc11base/__init__.py new file mode 100644 index 0000000..5dfc23a --- /dev/null +++ b/jsonrpc11base/__init__.py @@ -0,0 +1,6 @@ +from jsonrpc11base.main import JSONRPCService +import jsonrpc11base.exceptions as exceptions +import jsonrpc11base.errors as errors + +# Exported names: +__all__ = ['JSONRPCService', 'exceptions', 'errors'] diff --git a/jsonrpc11base/errors.py b/jsonrpc11base/errors.py new file mode 100644 index 0000000..8f76221 --- /dev/null +++ b/jsonrpc11base/errors.py @@ -0,0 +1,233 @@ +from typing import Optional +from jsonrpc11base.types import Identifier + + +# =============================================================================== +# Errors +# +# The error-codes -32768 .. -32000 (inclusive) are reserved for pre-defined +# errors. +# +# Any error-code within this range not defined explicitly below is reserved +# for future use +# =============================================================================== + +# Reference: https://www.jsonrpc.org/specification#error_object +RPC_ERRORS = { + # Invalid JSON was received. An error occurred on the server while parsing the JSON text. + -32700: 'Parse error', + # The JSON sent is not a valid Request object. + # Note that this message uses proper-cased "Request", as per the spec. This is the one + # exception to sentence-casing for error messages. + -32600: 'Invalid Request', + # The method does not exist / is not available. + -32601: 'Method not found', + # Invalid method parameter(s). + -32602: 'Invalid params', + # Internal JSON-RPC error. + -32603: 'Internal error', + # -32000 to -32099 to Reserved for implementation-defined server-errors. + # Unspecified, but should have it's own error message + -32000: 'Server error' +} + + +class JSONRPCError(Exception): + """ + JSONRPCError class based on the JSON-RPC 2.0 specs. + + code - number + message - string + data - object + """ + code: int = 0 + message: Optional[str] = None + error: Optional[dict] = None + + def to_json(self): + """Return the Exception data in a format for JSON-RPC.""" + + error = {'name': 'JSONRPCError', + 'code': self.code, + 'message': str(self.message)} + + if self.error is not None: + error['error'] = self.error + + return error + +# Standard Errors + + +class ParseError(JSONRPCError): + """Invalid JSON. An error occurred on the server while parsing the JSON text.""" + code = -32700 + message = 'Parse error' + + +class InvalidRequestError(JSONRPCError): + """The received JSON is not a valid JSON-RPC Request.""" + code = -32600 + message = 'Invalid Request' + + +class MethodNotFoundError(JSONRPCError): + """The requested remote-procedure does not exist / is not available.""" + code = -32601 + message = 'Method not found' + + def __init__(self, method, available_methods): + self.error = { + 'method': method, + 'available_methods': available_methods + } + + +class InvalidParamsError(JSONRPCError): + """Invalid method parameters.""" + code = -32602 + message = 'Invalid params' + + def __init__(self, message=None, path=None, value=None): + self.error = {} + if message is not None: + self.error['message'] = message + if path is not None: + self.error['path'] = path + if value is not None: + self.error['value'] = value + + +class InternalError(JSONRPCError): + """Internal JSON-RPC error.""" + code = -32603 + message = 'Internal error' + + +# Server Errors +# The server may specify any additional errors from -32000 to -32099. + + +class ServerError(JSONRPCError): + """Implementation defined server error -32000 through -32099""" + code = -32000 + message = 'Server error' + + def __init__(self, message): + self.error = { + 'message': message + } + + +class ReservedErrorCodeServerError(ServerError): + """Generic server error.""" + code = -32001 + message = 'Reserved error code' + + def __init__(self, message, bad_code=None): + super().__init__(message) + if bad_code is not None: + self.error['bad_code'] = bad_code + + +class InvalidResultServerError(ServerError): + """Generic server error.""" + code = -32002 + message = 'Invalid result' + + def __init__(self, message, path=None, value=None): + super().__init__(message) + if path is not None: + self.error['path'] = path + if value is not None: + self.error['value'] = value + +# +# class ServerError_AuthenticationRequired(CustomServerError): +# """Generic server error.""" +# code = -32003 +# message = 'Authentication required' + + +# The api may use any error code outside the reserved range -32000 too -32768. +# The api should subclass the APIError exception for each type of +# error and associate a code with that error. + + +class APIError(Exception): + """ + APIError class based on the JSON-RPC 1.1 specs. + Should not be used directly, but subclassed. + + code - number + message - string + error - object + """ + code: int = 1 + message: str = 'API error' + error: Optional[dict] = None + + def to_json(self): + """Return the Exception data in a format for JSON-RPC.""" + + error = {'name': 'APIError', + 'code': self.code, + 'message': self.message} + + if self.error is not None: + error['error'] = self.error + + return error + + +def make_standard_jsonrpc_error(code: int, + error: Optional[dict] = None): + """ + Makes a JRON-RPC 1.1. compliant error + """ + jsonrpc_error = { + 'name': 'JSONRPCError', + 'code': code, + 'message': RPC_ERRORS[code] + } + + if error is not None: + jsonrpc_error['error'] = error + + return jsonrpc_error + + +def make_custom_jsonrpc_error(code: int, + message: Optional[str], + error: Optional[dict] = None): + """ + Makes a JRON-RPC 1.1. compliant error + """ + + jsonrpc_error = { + 'name': 'JSONRPCError', + 'code': code, + 'message': message + } + + if error is not None: + jsonrpc_error['error'] = error + + return jsonrpc_error + + +def make_jsonrpc_error_response(error: Optional[dict], + id: Optional[Identifier] = None): + """ + Makes a JRON-RPC 1.1. compliant error + """ + + response_data = { + 'version': '1.1', + 'error': error + } + + if id is not None: + response_data['id'] = id + + return response_data diff --git a/jsonrpc11base/exceptions.py b/jsonrpc11base/exceptions.py new file mode 100644 index 0000000..28ea8af --- /dev/null +++ b/jsonrpc11base/exceptions.py @@ -0,0 +1,32 @@ +""" +Exception classes +""" + + +class JSONRPCBaseError(RuntimeError): + def __init__(self, message): + self.message = message + super().__init__(self.message) + + def __str__(self): + return self.message + + +class InvalidSchemaError(JSONRPCBaseError): + """Invalid JSON-Schema data.""" + pass + + +class InvalidServerErrorCode(JSONRPCBaseError): + """Invalid custom server error code (must be -32000 - -32099).""" + pass + + +class DuplicateMethodName(JSONRPCBaseError): + """User tried to register two methods of the same name to the same service.""" + pass + + +class InvalidFileType(JSONRPCBaseError): + """Invalid file extension""" + pass diff --git a/jsonrpc11base/jsonrpc_schema/jsonrpc11.json b/jsonrpc11base/jsonrpc_schema/jsonrpc11.json new file mode 100644 index 0000000..0342630 --- /dev/null +++ b/jsonrpc11base/jsonrpc_schema/jsonrpc11.json @@ -0,0 +1,153 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JSON-RPC Request Schema", + "description": "JSON-Schema that validates a JSON-RPC 1.1 request", + "definitions": { + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "version", + "method" + ], + "properties": { + "version": { + "const": "1.1" + }, + "method": { + "type": "string", + "minLength": 1 + }, + "id": { + "type": [ + "number", + "string", + "boolean", + "array", + "object", + "null" + ] + }, + "params": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "array" + } + ] + } + } + }, + "result": { + "type": "object", + "additionalProperties": false, + "required": [ + "version", + "result" + ], + "properties": { + "version": { + "const": "1.1" + }, + "id": { + "type": [ + "integer", + "string" + ] + }, + "result": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "array" + }, + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + } + } + }, + "errorObject": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "code", + "message" + ], + "properties": { + "name": { + "const": "JSONRPCError" + }, + "code": { + "type": "number" + }, + "message": { + "type": "string" + }, + "error": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + }, + "error": { + "type": "object", + "additionalProperties": false, + "required": [ + "version", + "error" + ], + "properties": { + "version": { + "const": "1.1" + }, + "id": { + "type": [ + "integer", + "string" + ] + }, + "error": { + "$ref": "#definitions/errorObject" + } + } + }, + "response": { + "oneOf": [ + { + "$ref": "#definitions/result" + }, + { + "$ref": "#definitions/error" + } + ] + } + } +} \ No newline at end of file diff --git a/jsonrpc11base/jsonrpc_schema/request.json b/jsonrpc11base/jsonrpc_schema/request.json new file mode 100644 index 0000000..55944da --- /dev/null +++ b/jsonrpc11base/jsonrpc_schema/request.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JSON-RPC Request Schema", + "description": "JSON-Schema that validates a JSON-RPC 1.1 request", + "$ref": "jsonrpc11.json#definitions/request" +} \ No newline at end of file diff --git a/jsonrpc11base/jsonrpc_schema/response.json b/jsonrpc11base/jsonrpc_schema/response.json new file mode 100644 index 0000000..a46d1a8 --- /dev/null +++ b/jsonrpc11base/jsonrpc_schema/response.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JSON-RPC Request Schema", + "description": "JSON-Schema that validates a JSON-RPC 1.1 response", + "oneOf": [ + { + "$ref": "jsonrpc11.json#definitions/result" + }, + { + "$ref": "jsonrpc11.json#definitions/error" + } + ] +} \ No newline at end of file diff --git a/jsonrpc11base/main.py b/jsonrpc11base/main.py new file mode 100644 index 0000000..866f878 --- /dev/null +++ b/jsonrpc11base/main.py @@ -0,0 +1,323 @@ +""" +Simple JSON-RPC service without transport layer + +See README.md for details + +Uses Google Style Python docstrings: + https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings +""" +from jsonrpc11base.service_description import ServiceDescription +import jsonrpc11base.validation.validation as validation +import json +import os +import logging + +from typing import Callable, Optional, Union, Dict + +import jsonrpc11base.exceptions as exceptions +import traceback +from jsonrpc11base.validation.schema import Schema, SchemaError +from jsonrpc11base.errors import (make_standard_jsonrpc_error, make_custom_jsonrpc_error, + make_jsonrpc_error_response, + InvalidParamsError, JSONRPCError, APIError, + MethodNotFoundError, + ReservedErrorCodeServerError, InvalidResultServerError) +from jsonrpc11base.types import (MethodRequest, MethodResult) +from jsonrpc11base.method import Method + +log = logging.getLogger(__name__) + + +class JSONRPCService(object): + """ + The JSONRPCService class is a JSON-RPC 1.1 implementation + """ + def __init__(self, + description: ServiceDescription, + schema_dir: Optional[Union[str, None]] = None, + validate_params: bool = False, + validate_result: bool = False): + """ + Initialize a new JSONRPCService object. + + Args: + description: A ServiceDescription instance + schema_dir: A directory path in which service schemas + may be found + validate_params: A boolean flag controlling whether parameters are + validated or not; defaults to False + validate_result: A boolean flag controlling whether the result is + validated or not; defaults to False + """ + # Initialize global jsonrpc schemas, which validate the overall + # JSON-RPC 1.1 structures. These schemas are built-in. + self.jsonrpc_schemas = Schema(os.path.abspath( + os.path.dirname(__file__) + '/jsonrpc_schema')) + + # Load the optional service validation jsonschemas. If no schemas + # are provided in the schema directory, service params and results + # are not validated. + if schema_dir is not None: + self.service_validation = validation.Validation(schema_dir=schema_dir) + else: + self.service_validation = None + + system_schema_dir = os.path.abspath( + os.path.dirname(__file__) + '/system_schema') + self.system_validation = validation.Validation(schema_dir=system_schema_dir) + + self.method_registry: Dict[str, Method] = {} + self.system_method_registry: Dict[str, Method] = {} + + # Add the built-in "system.describe" method + self.add(self.handle_system_describe, 'system.describe', system=True) + + if self.service_validation is None: + if validate_params: + raise TypeError('May not validate params with no schema_dir provided') + if validate_result: + raise TypeError('May not validate result with no schema_dir provided') + + self.validate_params = validate_params + self.validate_result = validate_result + + self.description = description + + def add(self, func: Callable, name: Optional[str] = None, system: bool = False): + """ + Adds a new method to the jsonrpc service. If name argument is not + given, function's own name will be used. + + Example: + service.add(myfunc, name='my_function') + + Args: + func: required python function handler to call for this method + name: name of the method (optional, defaults to the function's name) + """ + function_name = name if name else func.__name__ + registry = self.method_registry if not system else self.system_method_registry + if function_name in registry: + msg = f'Method "{function_name}" already registered' + raise exceptions.DuplicateMethodName(msg) + registry[function_name] = Method(func) + + def call(self, jsondata: str, options=None) -> str: + """ + Calls jsonrpc service's method and returns its return value in a JSON + string or None if there is none. + + Args: + jsondata: JSON-RPC 1.1 request body (raw string) + options: any additional object to pass along to the handler function as the second arg + + Returns: + The JSON-RPC 1.1 response as a raw JSON string. + Will not throw an exception. + """ + try: + request_data = json.loads(jsondata) + except ValueError as err: + resp = make_jsonrpc_error_response( + make_standard_jsonrpc_error(-32700, error={'message': str(err)})) + return json.dumps(resp) + + result = self.call_py(request_data, options) + if result is not None: + return json.dumps(result) + + def find_method(self, method_name): + method_parts = method_name.split('.') + + is_system_method = False + if len(method_parts) == 2: + if method_parts[0] == 'system': + is_system_method = True + + registry = self.method_registry if not is_system_method else self.system_method_registry + + if method_name not in registry: + methods = list(registry.keys()) + raise MethodNotFoundError(method=method_name, available_methods=methods) + + return [registry[method_name], is_system_method] + + # Wraps the process of method invocation and validation + def do_method(self, method_name, params, options): + method, is_system_method = self.find_method(method_name) + + if is_system_method: + validator = self.system_validation + else: + validator = self.service_validation + + if validator is not None: + if validator.has_params_validation(method_name): + if params is None: + raise InvalidParamsError( + message='Method has parameters specified, but none were provided' + ) + else: + validator.validate_params(method_name, params) + return [method.call(params, options), is_system_method] + elif validator.has_absent_params_validation(method_name): + if params is None: + validator.validate_absent_params(method_name) + return [method.call(None, options), is_system_method] + else: + raise InvalidParamsError( + message=('Method has no parameters specified, ' + 'but arguments were provided') + ) + else: + # If validation is provided, all methods must have validation. + raise InvalidParamsError( + message='Validation is enabled, but no parameter validator was provided' + ) + else: + return [method.call(params, options), is_system_method] + + def call_py(self, req_data: MethodRequest, options=None) -> MethodResult: + """ + Call a method in the service and return the RPC response. The _py suffix indicates + that input and output are Python objects, not strings. In other words, the "call" + method wraps "call_py" by dealing with strings, allowing "call_py" to ignore JSON + conversion. + + Args: + req_data: JSON-RPC 1.1 request data as a python object + options: Any optional additional, application-specific data, which will be + passed straight through to the rpc method. + + Returns: + The JSON-RPC 1.1 response as a python object. + Will not throw an exception. + """ + # Validate the request data using a json-schema + try: + if self.validate_params: + self.jsonrpc_schemas.validate('request', req_data) + except SchemaError as ex: + error = make_standard_jsonrpc_error(-32600, error={ + 'message': ex.message, + 'path': ex.path, + 'value': ex.value + }) + # May seem pointless, but in case the request does not validate, yet it is an + # object, it might have an id to use in the response. + if isinstance(req_data, dict): + return make_jsonrpc_error_response(error, req_data.get('id')) + else: + return make_jsonrpc_error_response(error) + + request_id = req_data.get('id') + + # Note that we can be cavalier, assuming that the 'method' + # is available in the request, since we've already validated it, + # and 'method' is required. + method_name = req_data['method'] + + # Note that params is optional, but must be a JSON + # array or object (enforced with the jsonschema), so + # if it is absent, and thus None here, we know it isn't + # JSON null, and None really means none (and is not the + # imo misuse of None for JSON null) + params = req_data.get('params') + + # Wraps the process of results validation + def do_result(result, system_method): + if not self.validate_result: + return result + + if system_method: + validator = self.system_validation + else: + validator = self.service_validation + + if not validator.has_result_validation(method_name): + # If validation is provided, all methods must have validation. + raise InvalidParamsError( + message='Validation is enabled, but no result validator was provided' + ) + + if validator.has_absent_result_validation(method_name): + # If the method should have no result, we just set it to null. + # JSONRPC 1.1 mentions the value 'nil' for methods without a result + # value, but the result is also required, so we need to populate + # it with something ... null is a good choice. + # The caller should ignore the value. + if result is None: + return None + else: + raise InvalidResultServerError( + message=('The method is specified to not return a result, ' + 'yet a value was returned'), + value=result + ) + + validator.validate_result(method_name, result) + return result + + # Wraps the process of creating a result + def make_result_response(result): + response_data = { + 'version': '1.1', + 'result': result + } + if request_id is not None: + response_data['id'] = request_id + return response_data + + # Wraps error object construction + def make_error_response(error_data): + # From closure + if 'error' not in error_data: + error_data['error'] = {} + error_data['error']['method'] = method_name + + return make_jsonrpc_error_response(error_data, request_id) + + try: + result, system_method = self.do_method(method_name, params, options) + return make_result_response(do_result(result, system_method)) + # Covers a method throwing any specific jsonrpc predefined + # exception. + except JSONRPCError as e: + return make_error_response(e.to_json()) + # Covers a method throwing a jsonrpc error which is not + # within the range of predefined jsonrpc errors + except APIError as e: + # Which, sigh, itself may be an error if the app used + # an error code within the reserved range. + if -32768 <= e.code <= -32000: + err = ReservedErrorCodeServerError( + message=( + 'An error code was issued by the api which conflicts with ', + 'the reserved range between -32768 and -3200' + ), + bad_code=e.code + ) + return make_error_response(err.to_json()) + else: + return make_error_response(e.to_json()) + # Finally, catch any programming errors + except Exception as ex: + message = getattr(ex, 'message', str(ex)) + error = {'message': ('An unexpected exception was caught ' + 'executing the method'), + 'exception_message': message or 'Unknown exception', + 'traceback': traceback.format_exc(limit=1000).split('\n')} + error = make_custom_jsonrpc_error(-32002, + message='Exception calling method', + error=error) + return make_error_response(error) + + # TODO: break off into a service class + + # TODO: move to a service module + + def handle_system_describe(self, options) -> dict: + """ + Built-in method handler that shows all methods and type schemas for the service in a dict. + """ + return self.description.to_json() diff --git a/jsonrpc11base/method.py b/jsonrpc11base/method.py new file mode 100644 index 0000000..7c3bd28 --- /dev/null +++ b/jsonrpc11base/method.py @@ -0,0 +1,32 @@ +from typing import Callable +import time + + +class Method(object): + """ + Method function handler, and any other metadata we may need in the future + """ + method_implementation: Callable + call_count: int + cumulative_call_time: float + error_count: int + + def __init__(self, method: Callable): + self.method_implementation = method + self.call_count = 0 + self.cumulative_call_time = 0 + self.error_count = 0 + + def call(self, params, options): + self.call_count += 1 + call_started = time.time() + try: + if params is None: + result = self.method_implementation(options) + else: + result = self.method_implementation(params, options) + self.cumulative_call_time = time.time() - call_started + return result + except Exception as e: + self.error_count = 0 + raise e diff --git a/jsonrpc11base/service_description.py b/jsonrpc11base/service_description.py new file mode 100644 index 0000000..c61eef9 --- /dev/null +++ b/jsonrpc11base/service_description.py @@ -0,0 +1,20 @@ +class ServiceDescription(object): + def __init__(self, name, id, version=None, summary=None): + self.name = name + self.id = id + self.version = version + self.summary = summary + + def to_json(self): + data = { + 'sdversion': '1.0', + 'name': self.name, + 'id': self.id + } + if (self.version is not None): + data['version'] = self.version + + if (self.summary is not None): + data['summary'] = self.summary + + return data diff --git a/jsonrpc11base/system_schema/system.describe.params.json b/jsonrpc11base/system_schema/system.describe.params.json new file mode 100644 index 0000000..e69de29 diff --git a/jsonrpc11base/system_schema/system.describe.result.json b/jsonrpc11base/system_schema/system.describe.result.json new file mode 100644 index 0000000..36052a9 --- /dev/null +++ b/jsonrpc11base/system_schema/system.describe.result.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "Test service schema", + "type": "object", + "additionalProperties": true +} \ No newline at end of file diff --git a/jsonrpc11base/types.py b/jsonrpc11base/types.py new file mode 100644 index 0000000..b96bd80 --- /dev/null +++ b/jsonrpc11base/types.py @@ -0,0 +1,16 @@ +from typing import Optional, Union + + +# RPC ID field +Identifier = Union[int, str, dict, list, bool, None] + +# RPC params or result field +ParamsResult = Optional[Union[dict, list]] + +# Request structure +MethodRequest = dict + +# Result structure for a JSON-RPC 1.1 request +# Will be None if the request was a notification +# Otherwise a structure (dict) +MethodResult = Optional[dict] diff --git a/jsonrpc11base/validation/schema.py b/jsonrpc11base/validation/schema.py new file mode 100644 index 0000000..ac3632d --- /dev/null +++ b/jsonrpc11base/validation/schema.py @@ -0,0 +1,81 @@ +from jsonschema import validate, RefResolver +from jsonschema.exceptions import ValidationError +import os +import glob +import json + +DEFAULT_SCHEMA_DIR = 'schemas' + + +class SchemaError(Exception): + def __init__(self, message, path, value): + self.message = message + self.path = path + self.value = value + + +class Schema(object): + def __init__(self, schema_dir): + if schema_dir is None: + raise Exception('schema_dir is required') + + self.schema_dir = os.path.abspath(schema_dir) + + self.resolver = RefResolver(f'file://{schema_dir}/', None) + + self.schemas = self.load() + + def load(self): + schemas = {} + for file_path in glob.glob(f'{self.schema_dir}/*.json'): + file_base_name = os.path.splitext(os.path.basename(file_path))[0] + + with open(file_path) as fd: + schema_text = fd.read() + if len(schema_text) == 0: + # this means the associated value must + # be absent + schema = { + 'absent': True + } + else: + schema = { + 'schema': json.loads(schema_text) + } + schemas[file_base_name] = schema + return schemas + + def validate_absent(self, schema_key): + """ Used in the case in which the value is absent. """ + schema = self.schemas.get(schema_key, None) + if schema is None: + return False + return schema.get('absent', False) + + def validate(self, schema_key, value): + schema_wrapper = self.schemas.get(schema_key) + + if schema_wrapper is None: + raise SchemaError( + f'Schema "{schema_key}" does not exist', + '', + value + ) + + if schema_wrapper.get('absent') is True: + raise SchemaError( + f'Schema "{schema_key}" specifies the the value must be absent', + '', + value + ) + + schema = schema_wrapper.get('schema') + try: + validate(instance=value, schema=schema, resolver=self.resolver) + except ValidationError as ex: + message = ex.message + path = '.'.join(map(str, ex.absolute_schema_path)) + raise SchemaError(message, path, ex.validator_value) + + def get(self, schema_name, default_value=None): + return self.schemas.get(schema_name, default_value) diff --git a/jsonrpc11base/validation/validation.py b/jsonrpc11base/validation/validation.py new file mode 100644 index 0000000..e26f021 --- /dev/null +++ b/jsonrpc11base/validation/validation.py @@ -0,0 +1,67 @@ +from .schema import Schema, SchemaError +from jsonrpc11base.errors import InvalidParamsError, InvalidResultServerError + + +class Validation(object): + def __init__(self, schema_dir): + self.schema = Schema(schema_dir) + + def has_params_validation(self, method_name): + schema_key = method_name + '.params' + schema = self.schema.get(schema_key) + if schema is None: + return False + else: + return schema.get('schema', False) + + def has_absent_params_validation(self, method_name): + schema_key = method_name + '.params' + schema = self.schema.get(schema_key) + if schema is None: + return False + else: + return schema.get('absent', False) + + def has_result_validation(self, method_name): + schema_key = method_name + '.result' + if self.schema.get(schema_key) is None: + return False + else: + return True + + def has_absent_result_validation(self, method_name): + schema_key = method_name + '.result' + schema = self.schema.get(schema_key) + if schema is None: + return False + else: + return schema.get('absent', False) + + def validate_params(self, method_name, data): + schema_key = method_name + '.params' + try: + self.schema.validate(schema_key, data) + except SchemaError as ex: + raise InvalidParamsError( + message=ex.message, + path=ex.path, + value=ex.value + ) + + def validate_absent_params(self, method_name): + schema_key = method_name + '.params' + if self.schema.validate_absent(schema_key) is not True: + raise InvalidParamsError( + message='Params must be provided for this method' + ) + + def validate_result(self, method_name, data): + schema_key = method_name + '.result' + try: + self.schema.validate(schema_key, data) + except SchemaError as ex: + raise InvalidResultServerError( + message=ex.message, + path=ex.path, + value=ex.value + ) From 36047d648b5d1516fefd6af28343a03c9168dbb8 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 14:41:27 -0700 Subject: [PATCH 11/37] revert previous jsonrpc changes --- src/search1_conversion/convert_params.py | 2 +- src/search1_rpc/errors.py | 28 +------------------ src/search1_rpc/service.py | 4 +-- src/search1_rpc/service_description.py | 20 ------------- .../test_search1_convert_params.py | 2 +- 5 files changed, 5 insertions(+), 51 deletions(-) delete mode 100644 src/search1_rpc/service_description.py diff --git a/src/search1_conversion/convert_params.py b/src/search1_conversion/convert_params.py index c9b6d16..40e62ba 100644 --- a/src/search1_conversion/convert_params.py +++ b/src/search1_conversion/convert_params.py @@ -35,7 +35,7 @@ """ from src.utils.obj_utils import get_any -from jsonrpcbase import InvalidParamsError +from jsonrpc11base.errors import InvalidParamsError # Mapping of special sorting properties names from the Java API to search2 key names _SORT_PROP_MAPPING = { diff --git a/src/search1_rpc/errors.py b/src/search1_rpc/errors.py index e918181..1e9ecf3 100644 --- a/src/search1_rpc/errors.py +++ b/src/search1_rpc/errors.py @@ -1,33 +1,7 @@ -from typing import Optional +from jsonrpc11base.errors import APIError from src import exceptions -class APIError(Exception): - """ - APIError class based on the JSON-RPC 1.1 specs. - Should not be used directly, but subclassed. - - code - number - message - string - error - object - """ - code: int = 1 - message: str = 'API error' - error: Optional[dict] = None - - def to_json(self): - """Return the Exception data in a format for JSON-RPC.""" - - error = {'name': 'APIError', - 'code': self.code, - 'message': self.message} - - if self.error is not None: - error['error'] = self.error - - return error - - class UnknownTypeError(APIError): code = 1000 message = 'Unknown type' diff --git a/src/search1_rpc/service.py b/src/search1_rpc/service.py index 2123bc1..2abdf27 100644 --- a/src/search1_rpc/service.py +++ b/src/search1_rpc/service.py @@ -19,8 +19,8 @@ import time import os -from jsonrpcbase import JSONRPCService -from src.search1_rpc.service_description import ServiceDescription +from jsonrpc11base import JSONRPCService +from jsonrpc11base.service_description import ServiceDescription from src.es_client.query import search from src.search1_conversion import convert_params, convert_result from src.utils.logger import logger diff --git a/src/search1_rpc/service_description.py b/src/search1_rpc/service_description.py deleted file mode 100644 index c61eef9..0000000 --- a/src/search1_rpc/service_description.py +++ /dev/null @@ -1,20 +0,0 @@ -class ServiceDescription(object): - def __init__(self, name, id, version=None, summary=None): - self.name = name - self.id = id - self.version = version - self.summary = summary - - def to_json(self): - data = { - 'sdversion': '1.0', - 'name': self.name, - 'id': self.id - } - if (self.version is not None): - data['version'] = self.version - - if (self.summary is not None): - data['summary'] = self.summary - - return data diff --git a/tests/unit/search1_conversion/test_search1_convert_params.py b/tests/unit/search1_conversion/test_search1_convert_params.py index 7f8b15a..0142b7b 100644 --- a/tests/unit/search1_conversion/test_search1_convert_params.py +++ b/tests/unit/search1_conversion/test_search1_convert_params.py @@ -1,7 +1,7 @@ import pytest from src.search1_conversion import convert_params -from jsonrpcbase import InvalidParamsError +from jsonrpc11base.errors import InvalidParamsError def test_search_objects_valid(): From c2d35ba3ae833505b34b47f315b125092ada679a Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 15:07:49 -0700 Subject: [PATCH 12/37] comment mypy --- scripts/run_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_tests b/scripts/run_tests index 982f93c..7779a35 100755 --- a/scripts/run_tests +++ b/scripts/run_tests @@ -9,7 +9,7 @@ export WORKSPACE_URL="http://localhost:5555/ws" path=${@:-"tests/unit"} poetry run flake8 src tests -poetry run mypy --ignore-missing-imports src/**/*.py +# poetry run mypy --ignore-missing-imports src/**/*.py poetry run bandit -r src echo "Running tests in $path" From 48a2198e19b7b483af45fbb76c76007b24f47e59 Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 17:10:29 -0700 Subject: [PATCH 13/37] copy over jsonrpcbase --- jsonrpcbase/__init__.py | 5 + jsonrpcbase/exceptions.py | 32 ++++ jsonrpcbase/main.py | 310 ++++++++++++++++++++++++++++++++++++++ jsonrpcbase/types.py | 34 +++++ jsonrpcbase/utils.py | 124 +++++++++++++++ 5 files changed, 505 insertions(+) create mode 100644 jsonrpcbase/__init__.py create mode 100644 jsonrpcbase/exceptions.py create mode 100644 jsonrpcbase/main.py create mode 100644 jsonrpcbase/types.py create mode 100644 jsonrpcbase/utils.py diff --git a/jsonrpcbase/__init__.py b/jsonrpcbase/__init__.py new file mode 100644 index 0000000..a3fbdb1 --- /dev/null +++ b/jsonrpcbase/__init__.py @@ -0,0 +1,5 @@ +from jsonrpcbase.main import JSONRPCService +import jsonrpcbase.exceptions as exceptions + +# Exported names: +__all__ = ['JSONRPCService', 'exceptions'] diff --git a/jsonrpcbase/exceptions.py b/jsonrpcbase/exceptions.py new file mode 100644 index 0000000..28ea8af --- /dev/null +++ b/jsonrpcbase/exceptions.py @@ -0,0 +1,32 @@ +""" +Exception classes +""" + + +class JSONRPCBaseError(RuntimeError): + def __init__(self, message): + self.message = message + super().__init__(self.message) + + def __str__(self): + return self.message + + +class InvalidSchemaError(JSONRPCBaseError): + """Invalid JSON-Schema data.""" + pass + + +class InvalidServerErrorCode(JSONRPCBaseError): + """Invalid custom server error code (must be -32000 - -32099).""" + pass + + +class DuplicateMethodName(JSONRPCBaseError): + """User tried to register two methods of the same name to the same service.""" + pass + + +class InvalidFileType(JSONRPCBaseError): + """Invalid file extension""" + pass diff --git a/jsonrpcbase/main.py b/jsonrpcbase/main.py new file mode 100644 index 0000000..fb405be --- /dev/null +++ b/jsonrpcbase/main.py @@ -0,0 +1,310 @@ +""" +Simple JSON-RPC service without transport layer + +See README.md for details + +Uses Google Style Python docstrings: + https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings +""" +import json +import jsonschema +import logging + +from typing import Callable, Optional, List, Union + +import jsonrpcbase.exceptions as exceptions +import jsonrpcbase.types as types +import jsonrpcbase.utils as utils + +# Reference: https://www.jsonrpc.org/specification +REQUEST_SCHEMA = { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JSON-RPC Request Schema", + "description": "JSON-Schema that validates a JSON-RPC 2.0 request body (non-batch requests)", + "type": "object", + "additionalProperties": False, + "required": ["jsonrpc", "method"], + "properties": { + "jsonrpc": { + "const": "2.0" + }, + "method": { + "type": "string", + "minLength": 1, + }, + "id": { + "type": ["integer", "string"] + }, + "params": { + "anyOf": [{"type": "object"}, {"type": "array"}] + } + } +} + +# Reference: https://www.jsonrpc.org/specification#error_object +RPC_ERRORS = { + # Invalid JSON was received. An error occurred on the server while parsing the JSON text. + -32700: 'Parse error', + # The JSON sent is not a valid Request object. + -32600: 'Invalid Request', + # The method does not exist / is not available. + -32601: 'Method not found', + # Invalid method parameter(s). + -32602: 'Invalid params', + # Internal JSON-RPC error. + -32603: 'Internal error', + # Reserved for implementation-defined server-errors. + -32000: 'Server error', +} + +log = logging.getLogger(__name__) + + +class JSONRPCService(object): + """ + The JSONRPCService class is a JSON-RPC + """ + + # JSON-Schema for the service + schema: dict + # Flag for development mode (validate result schemas) + development: bool + # Mapping of method name to function handler + method_data: types.MethodData + # Service name, description, version, etc + info: types.ServiceInfo + + def __init__(self, + info: Union[str, dict], + schema: Optional[Union[str, dict]] = None, + development: bool = False): + """ + Initialize a new JSONRPCService object. + + Args: + schema: JSON-Schema dict or path to a YAML or JSON file. + development: Flag if we are in development mode. Dev mode checks + all result schemas. + info: service name, description, and version. + """ + # Initialize service schema + self.schema = utils.load_schema(schema) + # A mapping of method name to python function and json-schema + self.method_data = { + 'rpc.discover': types.Method(method=self._handle_discover) + } + self.development = development + self.info = utils.load_service_info(info) + + def add(self, func: Callable, name: Optional[str] = None): + """ + Adds a new method to the jsonrpc service. If name argument is not + given, function's own name will be used. + + Example: + service.add(myfunc, name='my_function') + + Args: + func: required python function handler to call for this method + name: optional name of the method (defaults to the function's name) + schema: optional JSON-Schema for parameter validation + """ + fname = name if name else func.__name__ + if fname in self.method_data: + msg = f"Duplicate method name for JSON-RPC service: '{fname}'" + raise exceptions.DuplicateMethodName(msg) + self.method_data[fname] = types.Method(method=func) + + def call(self, jsondata: str, metadata=None) -> str: + """ + Calls jsonrpc service's method and returns its return value in a JSON + string or None if there is none. + + Args: + jsondata: JSON-RPC 2.0 request body (raw string) + metadata: any additional object to pass along to the handler function as the second arg + + Returns: + The JSON-RPC 2.0 response as a raw JSON string. + Will not throw an exception. + """ + try: + request_data = json.loads(jsondata) + except ValueError as err: + resp = self._err_response(-32700, err_data={'details': str(err)}, always_respond=True) + return json.dumps(resp) + result = self.call_py(request_data, metadata) + if result is not None: + return json.dumps(result) + + def call_py(self, req_data: types.MethodRequest, metadata=None) -> types.MethodResult: + """ + Call a method in the service and return the RPC response. This behaves + the same as call() except that the request and response are python + objects instead of JSON strings. + + Args: + req_data: JSON-RPC 2.0 request payload as a python object + metadata: Any optional additional data to send to the handler function + + Returns: + The JSON-RPC 2.0 response as a python object. + Returns None if the request is a notification. + Will not throw an exception. + """ + if isinstance(req_data, list): + if len(req_data) == 0: + err_data = {'details': 'Batch request array is empty'} + return self._err_response(-32600, err_data=err_data, always_respond=True) + return self._call_batch(req_data, metadata) + return self._call_single(req_data, metadata) + + def _call_single(self, req_data: dict, metadata) -> dict: + """ + Make a single method call (used in call_py() and _call_batch()) + Args: + req_data: JSON-RPC 2.0 parsed request parameter data + metadata: Any user-supplied additional data to be passed to the method handler + Returns: + JSON-RPC 2.0 result data. + Raises: + jsonschema.ValidationError + exceptions.InvalidServerErrorCode + """ + # Validate the request body using a json-schema + try: + jsonschema.validate(req_data, REQUEST_SCHEMA) + except jsonschema.exceptions.ValidationError as err: + log.exception(f'Invalid JSON-RPC request for {req_data}: {err}') + data = { + 'details': err.message, + } + return self._err_response(-32600, req_data, err_data=data, always_respond=True) + # Handle unknown method error + if req_data['method'] not in self.method_data: + # Missing method + meths = list(self.method_data.keys()) + err_data = {'available_methods': meths} + return self._err_response(-32601, req_data, err_data=err_data) + method = self.method_data[req_data['method']].method + params = req_data.get('params') + (params_schema, result_schema) = utils.get_method_schemas(self.schema, req_data['method']) + # Validate the parameters with the json-schema, if present + if (req_data['method'] in self.schema['definitions']['methods'] + and params_schema is None + and params is not None): + # If there is an entry for the method, but no params schema, then params must be absent + err_data = {'details': "Parameters not allowed"} + return self._err_response(-32602, req_data, err_data) + elif params_schema is not None: + # Allow referencing of definitions from the service schema + params_schema['definitions'] = self.schema['definitions'] + try: + jsonschema.validate(params, params_schema) + except jsonschema.exceptions.ValidationError as err: + # Invalid params error response + err_data = {'details': err.message, 'path': list(err.path)} + return self._err_response(-32602, req_data, err_data) + try: + result = method(params, metadata) + except Exception as err: + # Exception was raised inside the method. + log.exception(f"Method {req_data['method']} threw an exception: {err}") + err_data = {'method': req_data['method']} + if hasattr(err, 'message'): + err_data['details'] = err.message + code = -32000 # Server error + if hasattr(err, 'jsonrpc_code'): + code = err.jsonrpc_code + if code > -32000 or code < -32099: + msg = ( + f"Invalid server error code '{code}'; " + "must be in the range -32000 to -32099." + ) + raise exceptions.InvalidServerErrorCode(msg) + return self._err_response(code, req_data, err_data) + # Validate the result in development mode, if a result schema was supplied + if self.development and result_schema: + result_schema['definitions'] = self.schema['definitions'] + # Raises jsonschema.ValidationError + jsonschema.validate(result, result_schema) + _id = utils.response_id(req_data) + if type(_id) in (str, int): + # Return the result in JSON-RPC 2.0 response format + return { + 'id': _id, + 'jsonrpc': '2.0', + 'result': result, + } + else: + # Notification request; no results + return None + + def _call_batch(self, req_data: List[dict], metadata) -> Optional[List[dict]]: + """ + Make many method calls (used in call_py()) + """ + results = [] + for req in req_data: + resp = self._call_single(req, metadata) + # According to the spec, notification requests do not go in the result array + if resp is not None: + results.append(resp) + # Equivalent to something like `return results or None`, but let's be explicit: + if len(results) == 0: + # Every request was a notification + return None + else: + return results + + def _err_response(self, + code: int, + req_data: Optional[dict] = None, + err_data: Optional[dict] = None, + always_respond: bool = False) -> dict: + """ + Return a JSON-RPC 2.0 error response. The 'message' field is + autopopulated from the code based on values from the spec. + + Args: + code: JSON-RPC 2.0 error code + req_data: Request data as a python object + err_data: Optional 'data' field for the error response + always_respond: Even if there was no ID in the request, send a response + Returns: + JSON-RPC 2.0 error response as a python dict. + + ID behavior: + - If req_data is None and always_respond is True, then a response is + returned with 'id' of null + - If req_data is None and always_respond is False, then None is returned + - If req_data has a valid ID, then that is returned in the response + - If req_data does not have a valid ID and always_respond is True, + then 'id' is null in the response + - If req_data does not have a valid ID and always_response is False, then None is returned + """ + _id = utils.response_id(req_data) if req_data else None + if _id is None and not always_respond: + # Do not return error responses for notifications + return None + resp = { + 'jsonrpc': '2.0', + 'id': _id, + 'error': { + 'code': code, + 'message': RPC_ERRORS[code], + } + } + if err_data: + resp['error']['data'] = err_data + return resp + + def _handle_discover(self, params, meta) -> dict: + """ + Built-in method handler that shows all methods and type schemas for the service in a dict. + """ + ret: dict = {} + ret['schema'] = self.schema + ret['development_mode'] = self.development + ret['service_info'] = self.info + return ret diff --git a/jsonrpcbase/types.py b/jsonrpcbase/types.py new file mode 100644 index 0000000..c894f90 --- /dev/null +++ b/jsonrpcbase/types.py @@ -0,0 +1,34 @@ +from typing import Dict, List, Optional, Union, Callable, NamedTuple + + +class ServiceInfo(NamedTuple): + """ + Metadata about the whole service. + """ + title: str + description: str + version: str + + +class Method(NamedTuple): + """ + Method function handler, and any other metadata we may need in the future + """ + method: Callable + + +# Mapping of method name to a namedtuple of handler function and anything else we need +MethodData = Dict[str, Method] + +# RPC ID field +Identifier = Optional[Union[int, str]] +# RPC params or result field +ParamsResult = Optional[Union[dict, list]] + +# Request structure +MethodRequest = Union[dict, List[dict]] + +# Result structure for a JSON-RPC 2.0 request +# Will be None if the request was a notification +# Will be a list of results if request was batch +MethodResult = Optional[Union[dict, List[dict]]] diff --git a/jsonrpcbase/utils.py b/jsonrpcbase/utils.py new file mode 100644 index 0000000..8bc721a --- /dev/null +++ b/jsonrpcbase/utils.py @@ -0,0 +1,124 @@ +import json +import jsonschema +import os +import yaml + +from typing import Optional, Any, List, Union + +import jsonrpcbase.exceptions as exceptions + + +# Type of `obj` should be anything that has the __getitem__ method +def get_path(obj: Any, path: List[str]) -> Optional[Any]: + """ + Get a nested value by a series of keys inside some nested indexable + containers, returning None if the path does not exist, avoiding any errors. + Args: + obj: any indexable (has __getitem__ method) obj + path: list of accessors, such as dict keys or list indexes + Examples: + get_path([{'x': {'y': 1}}], [0, 'x', 'y']) -> 1 + """ + for key in path: + try: + obj = obj[key] + except Exception: + return None + return obj + + +def load_yaml_or_json(path: str) -> dict: + """ + Load yaml or json data from a file path into a python object + """ + ext = os.path.splitext(path)[1].lower() + if ext == '.yaml' or ext == '.yml': + with open(path) as fd: + ret = yaml.safe_load(fd) + elif ext == '.json': + with open(path) as fd: + ret = json.load(fd) + else: + msg = f'File at path {path} must be YAML or JSON; {ext} is invalid' + raise exceptions.InvalidFileType(msg) + return ret + + +def load_schema(schema: Union[str, dict]) -> dict: + """ + Load, parse, and validate a JSON-Schema from a YAML or JSON file path. + + Args: + schema: dict of schema or file path to a JSON or YAML file + Returns: + An in-memory, jsonschema-validated python object + + throws InvalidSchemaError + """ + if isinstance(schema, str): + schema = load_yaml_or_json(schema) + elif schema is None: + schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + } + # Validate the schema + jsonschema.Draft7Validator.check_schema(schema) + # Set some defaults + schema['definitions'] = schema.get('definitions', {}) + schema['definitions']['methods'] = schema['definitions'].get('methods', {}) + # Set service discovery schema + if 'rpc.discover' in schema['definitions']['methods']: + msg = "The `rpc.discover` method is reserved and should not be used" + raise exceptions.InvalidSchemaError(msg) + # Builtin method schemas + schema['definitions']['methods']['rpc.discover'] = {} + return schema + + +def load_service_info(service_info: Union[dict, str]): + """Load the service info data, possibly from a file path.""" + if isinstance(service_info, dict): + info = service_info + if isinstance(service_info, str): + info = load_yaml_or_json(service_info) + jsonschema.validate(info, { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": False, + "required": ["title", "version", "description"], + "properties": { + "title": {"type": "string"}, + "version": {"type": "string"}, + "description": {"type": "string"}, + } + }) + return info + + +def get_method_schemas(schema: dict, method_name: str): + """ + Get the params and result schema for a given method by name from the + service schema. + """ + params_path = ['definitions', 'methods', method_name, 'params'] + result_path = ['definitions', 'methods', method_name, 'result'] + params = get_path(schema, params_path) + result = get_path(schema, result_path) + # Clone the data so it can be safely mutated + params = dict(params) if params is not None else params + result = dict(result) if result is not None else result + return (params, result) + + +def response_id(req_data): + """ + Get the ID for the response from a JSON-RPC request + Return None if ID is missing or invalid + """ + _id = None + if isinstance(req_data, dict): + _id = req_data.get('id') + if type(_id) in (str, int): + return _id + else: + return None From 3233636dbcffb59b8af1a44354c4286788b30aab Mon Sep 17 00:00:00 2001 From: Sijie Date: Wed, 30 Apr 2025 17:11:33 -0700 Subject: [PATCH 14/37] remove jsonrpcbase dep --- poetry.lock | 16 +--------------- pyproject.toml | 1 - src/search2_rpc/service.py | 4 ++-- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index 464b915..8ed3f4b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -313,20 +313,6 @@ files = [ {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -[[package]] -name = "jsonrpcbase" -version = "0.2.0" -description = "Simple JSON-RPC service without transport layer" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "JSONRPCBase-0.2.0.tar.gz", hash = "sha256:7ea67fc1a7c87756e9a876e18a342e431e80d0ef3ba867dfd6f3fac5bf3fcc0d"}, -] - -[package.dependencies] -six = "*" - [[package]] name = "jsonschema" version = "3.2.0" @@ -994,4 +980,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "3.9.19" -content-hash = "1d1d76c95ec1723eab1ac9e329a0db3d9efa807cd2b3dbfe1a2029298660e4f4" +content-hash = "b231869281a3ce92439879268576bced832a5f0c29c4a2f0f7b0c680e28fe3cb" diff --git a/pyproject.toml b/pyproject.toml index 0b30c44..6b8ff44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ sanic = "20.12.2" requests = "2.25.1" jsonschema = "3.2.0" pyyaml = "6.0.1" -jsonrpcbase = "0.2.0" [tool.poetry.group.dev.dependencies] diff --git a/src/search2_rpc/service.py b/src/search2_rpc/service.py index 0a62c5d..4f54b77 100644 --- a/src/search2_rpc/service.py +++ b/src/search2_rpc/service.py @@ -1,18 +1,18 @@ """ JSON-RPC 2.0 service for the Search2 API """ -import jsonrpcbase import re import requests import time +from jsonrpcbase import JSONRPCService from src.es_client import search from src.utils.config import config from src.utils.logger import logger from src.search2_conversion import convert_params, convert_result from src.exceptions import ElasticsearchError -service = jsonrpcbase.JSONRPCService( +service = JSONRPCService( info={ 'title': 'Search API', 'description': 'Search API layer in front of Elasticsearch for KBase', From 392362a3ba3386e49d1ce71ffc16f79b0b7067d0 Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 2 May 2025 12:58:56 -0700 Subject: [PATCH 15/37] update pytest, pytest-cov dep --- poetry.lock | 119 +++++++++++++++++++++++++++++++------------------ pyproject.toml | 4 +- 2 files changed, 78 insertions(+), 45 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8ed3f4b..a51bc7d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,26 +12,13 @@ files = [ {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, ] -[[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] -markers = "sys_platform == \"win32\"" -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 = "20.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, @@ -161,9 +148,27 @@ files = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] +[package.dependencies] +toml = {version = "*", optional = true, markers = "extra == \"toml\""} + [package.extras] toml = ["toml"] +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "flake8" version = "3.8.4" @@ -488,18 +493,6 @@ files = [ [package.extras] dev = ["pre-commit", "tox"] -[[package]] -name = "py" -version = "1.10.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] -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 = "pycodestyle" version = "2.6.0" @@ -549,47 +542,45 @@ files = [ [[package]] name = "pytest" -version = "6.2.2" +version = "7.4.0" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, - {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<1.0.0a1" -py = ">=1.8.2" -toml = "*" +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", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "2.11.1" +version = "4.1.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"}, - {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"}, + {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" [package.extras] -testing = ["fields", "hunter", "process-tests (==2.0.2)", "pytest-xdist", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pyyaml" @@ -823,6 +814,48 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + [[package]] name = "typed-ast" version = "1.4.2" @@ -980,4 +1013,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "3.9.19" -content-hash = "b231869281a3ce92439879268576bced832a5f0c29c4a2f0f7b0c680e28fe3cb" +content-hash = "f56fab7e33b84b8071cb4dffbb9656a204507406d65183ac7207e974555f3933" diff --git a/pyproject.toml b/pyproject.toml index 6b8ff44..0529a2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,8 +19,8 @@ bandit = "1.7.0" mccabe = "0.6.1" flake8 = "3.8.4" coverage = "5.5" -pytest = "6.2.2" -pytest-cov = "2.11.1" +pytest = "7.4.0" +pytest-cov = "4.1.0" responses = "0.12.1" [build-system] From 5be7663ceac207a8dafa8d44ad16f0382a5b609b Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 2 May 2025 13:06:03 -0700 Subject: [PATCH 16/37] update test.yml --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 571398d..f58827d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Run tests +name: Run search_api2 tests on: pull_request: From 87f6454b88c4a2ac6b1b54d0517759b41ce46a8f Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 2 May 2025 16:55:18 -0700 Subject: [PATCH 17/37] update requests dep --- poetry.lock | 122 ++++++++++++++++++++++++++++++++++++++++++------- pyproject.toml | 2 +- 2 files changed, 107 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index a51bc7d..323f26e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -62,15 +62,105 @@ files = [ ] [[package]] -name = "chardet" -version = "4.0.0" -description = "Universal encoding detector for Python 2 and 3" +name = "charset-normalizer" +version = "3.4.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, ] [[package]] @@ -645,25 +735,25 @@ files = [ [[package]] name = "requests" -version = "2.25.1" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.27" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" [package.extras] -security = ["cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton ; sys_platform == \"win32\" and python_version == \"2.7\""] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "responses" @@ -1013,4 +1103,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "3.9.19" -content-hash = "f56fab7e33b84b8071cb4dffbb9656a204507406d65183ac7207e974555f3933" +content-hash = "fc1fabf3f4d5aef9bef7577ad84f8454d31770f859dd2f8cbdf251eb6f8ae10b" diff --git a/pyproject.toml b/pyproject.toml index 0529a2b..8eb23a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ license = "MIT" [tool.poetry.dependencies] python = "3.9.19" sanic = "20.12.2" -requests = "2.25.1" +requests = "2.32.3" jsonschema = "3.2.0" pyyaml = "6.0.1" From 2ad4f6994bfe8226c5574f79e1ee693946e46a8a Mon Sep 17 00:00:00 2001 From: Sijie Date: Mon, 5 May 2025 10:46:55 -0700 Subject: [PATCH 18/37] add debug for failed test --- tests/unit/es_client/test_es_client.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/unit/es_client/test_es_client.py b/tests/unit/es_client/test_es_client.py index f66db61..7d2fea3 100644 --- a/tests/unit/es_client/test_es_client.py +++ b/tests/unit/es_client/test_es_client.py @@ -18,7 +18,16 @@ def test_search_public_valid(services): 'only_public': True, 'track_total_hits': True, } - result = search(params, {'auth': None}) + print("entering search") + + try: + result = search(params, {'auth': None}) + except Exception as e: + print("search is wrong") + raise e + + print("pass search") + assert result['count'] == 4 assert result['search_time'] >= 0 assert result['aggregations'] == {} From fc9a2b39f93e44676c31224ff505acb05d5c4467 Mon Sep 17 00:00:00 2001 From: Sijie Date: Mon, 5 May 2025 10:54:45 -0700 Subject: [PATCH 19/37] make pytest fail early --- scripts/run_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_tests b/scripts/run_tests index 7779a35..80ab5d6 100755 --- a/scripts/run_tests +++ b/scripts/run_tests @@ -13,6 +13,6 @@ poetry run flake8 src tests poetry run bandit -r src echo "Running tests in $path" -poetry run pytest -vv --cov=./src --cov-report=xml $path +poetry run pytest -x -vv --cov=./src --cov-report=xml $path poetry run coverage html poetry run coverage report From b127c6278dc0054ef3ecb1c6b830d007c2be0208 Mon Sep 17 00:00:00 2001 From: Sijie Date: Mon, 5 May 2025 14:42:51 -0700 Subject: [PATCH 20/37] use docker compose --- tests/helpers/unit_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index 773c843..ee576af 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -26,7 +26,7 @@ def start_service(wait_for_url, wait_for_name): global container_out global container_err - cmd = "docker-compose --no-ansi up" + cmd = "docker compose --no-ansi up" logger.info(f'Running command:\n{cmd}') container_out = open("container.out", "w") container_err = open("container.err", "w") From d513b8092d0910841eacc2a495dac674fa7b11b9 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 6 May 2025 11:32:46 -0700 Subject: [PATCH 21/37] get all tests running fast --- scripts/run_tests | 2 +- tests/unit/es_client/test_es_client.py | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/scripts/run_tests b/scripts/run_tests index 80ab5d6..7779a35 100755 --- a/scripts/run_tests +++ b/scripts/run_tests @@ -13,6 +13,6 @@ poetry run flake8 src tests poetry run bandit -r src echo "Running tests in $path" -poetry run pytest -x -vv --cov=./src --cov-report=xml $path +poetry run pytest -vv --cov=./src --cov-report=xml $path poetry run coverage html poetry run coverage report diff --git a/tests/unit/es_client/test_es_client.py b/tests/unit/es_client/test_es_client.py index 7d2fea3..f66db61 100644 --- a/tests/unit/es_client/test_es_client.py +++ b/tests/unit/es_client/test_es_client.py @@ -18,16 +18,7 @@ def test_search_public_valid(services): 'only_public': True, 'track_total_hits': True, } - print("entering search") - - try: - result = search(params, {'auth': None}) - except Exception as e: - print("search is wrong") - raise e - - print("pass search") - + result = search(params, {'auth': None}) assert result['count'] == 4 assert result['search_time'] >= 0 assert result['aggregations'] == {} From e0bcc9329710202140f212011ab920b1b2ef2067 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 6 May 2025 12:56:15 -0700 Subject: [PATCH 22/37] fix unit tests --- jsonrpcbase/main.py | 2 ++ tests/unit/search2_rpc/test_search2_rpc.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/jsonrpcbase/main.py b/jsonrpcbase/main.py index fb405be..cf97556 100644 --- a/jsonrpcbase/main.py +++ b/jsonrpcbase/main.py @@ -55,6 +55,8 @@ -32603: 'Internal error', # Reserved for implementation-defined server-errors. -32000: 'Server error', + # Elasticsearch response error + -32003: 'Elasticsearch response error', } log = logging.getLogger(__name__) diff --git a/tests/unit/search2_rpc/test_search2_rpc.py b/tests/unit/search2_rpc/test_search2_rpc.py index 41c68ff..53241ad 100644 --- a/tests/unit/search2_rpc/test_search2_rpc.py +++ b/tests/unit/search2_rpc/test_search2_rpc.py @@ -50,7 +50,7 @@ def test_show_indexes_error(services): res = json.loads(result) assert res['error'] assert res['error']['code'] == -32003 - assert res['error']['message'] == 'Server error' + assert res['error']['message'] == 'Elasticsearch response error' assert res['error']['data']['method'] == 'show_indexes' From f1159c9be5ce3e00290e544451a8b2ada2d85070 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 6 May 2025 13:08:29 -0700 Subject: [PATCH 23/37] remove coverage dep --- poetry.lock | 2 +- pyproject.toml | 1 - scripts/run_tests | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 323f26e..6777b15 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1103,4 +1103,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "3.9.19" -content-hash = "fc1fabf3f4d5aef9bef7577ad84f8454d31770f859dd2f8cbdf251eb6f8ae10b" +content-hash = "f421877f04ade5b7261f6ddbd759a46ee190af0ec607c6f2ba4e17e5c642f8b8" diff --git a/pyproject.toml b/pyproject.toml index 8eb23a2..316bd99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ mypy = "0.812" bandit = "1.7.0" mccabe = "0.6.1" flake8 = "3.8.4" -coverage = "5.5" pytest = "7.4.0" pytest-cov = "4.1.0" responses = "0.12.1" diff --git a/scripts/run_tests b/scripts/run_tests index 7779a35..d4be161 100755 --- a/scripts/run_tests +++ b/scripts/run_tests @@ -13,6 +13,4 @@ poetry run flake8 src tests poetry run bandit -r src echo "Running tests in $path" -poetry run pytest -vv --cov=./src --cov-report=xml $path -poetry run coverage html -poetry run coverage report +poetry run pytest -vv --cov=./src --cov-report=term --cov-report=xml $path From 572cdbcdb417789c44d1ec92e4234db591bb0bed Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 13 May 2025 11:36:37 -0700 Subject: [PATCH 24/37] fix container cannot stop issue --- tests/helpers/integration_setup.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/helpers/integration_setup.py b/tests/helpers/integration_setup.py index c43b350..0e7da11 100644 --- a/tests/helpers/integration_setup.py +++ b/tests/helpers/integration_setup.py @@ -22,7 +22,7 @@ def start_service(app_url): # Build and start the app using docker-compose cwd = 'tests/integration/docker' logger.info(f'Running docker-compose file in "{cwd}"') - cmd = "docker-compose --no-ansi up" + cmd = "docker-compose --ansi never up" logger.info(f'Running command:\n{cmd}') container_out = open("container.out", "w") container_err = open("container.err", "w") @@ -40,11 +40,15 @@ def stop_service(): if container_process is not None: logger.info('Stopping container') - container_process.send_signal(signal.SIGTERM) + + # Stop and remove containers + cwd = 'tests/integration/docker' + subprocess.run("docker-compose --ansi never down", shell=True, check=True, cwd=cwd) + logger.info('Waiting until service has stopped...') - if not common.wait_for_line("container.err", - lambda line: 'Stopping' in line and 'done' in line, + if not common.wait_for_line("container.out", + lambda line: "exited with code 0" in line, timeout=stop_timeout, line_count=1): raise Exception(f'Container did not stop in the alloted time of {stop_timeout} seconds') From a899501868d2fdbac775f5782dd07acb9000fbb7 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 13 May 2025 11:37:19 -0700 Subject: [PATCH 25/37] update docker-compose file --- tests/integration/docker/docker-compose.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/integration/docker/docker-compose.yaml b/tests/integration/docker/docker-compose.yaml index 05e4be6..89d7407 100644 --- a/tests/integration/docker/docker-compose.yaml +++ b/tests/integration/docker/docker-compose.yaml @@ -1,13 +1,9 @@ -version: "3.4" - # This docker-compose is for developer workflows, not for running in production. -# This - networks: kbase-dev: - external: - name: kbase-dev + name: kbase-dev + external: true services: searchapi2: From 40d548e10d193894786f25b93ecff6cefae57f5a Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 13 May 2025 11:37:49 -0700 Subject: [PATCH 26/37] fix failed tests --- tests/integration/test_legacy_search_objects.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_legacy_search_objects.py b/tests/integration/test_legacy_search_objects.py index cd29a5b..eed2a25 100644 --- a/tests/integration/test_legacy_search_objects.py +++ b/tests/integration/test_legacy_search_objects.py @@ -154,15 +154,15 @@ def get_count(service, with_private, with_public): def test_search_objects_private_and_public_counts(service): - assert_counts(service, 1, 1, 12) + assert_counts(service, 1, 1, 21) def test_search_objects_private_counts(service): - assert_counts(service, 1, 0, 5) + assert_counts(service, 1, 0, 12) def test_search_objects_public_counts(service): - assert_counts(service, 0, 1, 9) + assert_counts(service, 0, 1, 11) def test_search_objects_neither_private_nor_public(service): From 20543612d0f78a70e12105a5c4f76cb0a2c9c681 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 13 May 2025 12:07:55 -0700 Subject: [PATCH 27/37] update integration-testing.md --- docs/integration-testing.md | 63 ++++++++++++++---------------- tests/helpers/integration_setup.py | 1 - 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/docs/integration-testing.md b/docs/integration-testing.md index 44df32d..e1ff4df 100644 --- a/docs/integration-testing.md +++ b/docs/integration-testing.md @@ -7,7 +7,7 @@ The integration tests run inside a Docker container. An associated ssh tunnel pr Although the integration test script will build the images if they are missing, the build can take a few minutes, which may cause the integration test script to time out. It is more reliable to simply build the containers first. ```bash -make build-integration-test-images +make build-dev-images ``` You can view the files `container.out` and `container.err` to monitor progress building the images. @@ -19,12 +19,12 @@ First you'll need to set up the required test parameters, which are provided as ```bash export WS_TOKEN="" export IP="" -export SHHOST="" +export SSHHOST="" export SSHUSER="" export SSHPASS="" ``` -> Note: For now the "test user" is `kbaseuitest`. As a kbase-ui dev for the password or a token. +> Note: For now, the "test user" is `kbaseuitest`. Ask a kbase-ui dev in the #ui channel for the password to obtain the `WS_TOKEN`. > TODO: We should establish a `searchtest` user, use it to create some narratives with data for indexing, and use that account for integration testing. @@ -32,7 +32,7 @@ export SSHPASS="" Running the tests is as simple as: ```bash -make integration-Tests +make integration-tests ``` The default logging level is "DEBUG" which can emit an annoying level of messages interspersed with test results. I prefer to run the tests like: @@ -44,38 +44,35 @@ LOGLEVEL=ERROR make integration-tests If all goes well you should see something like: ```bash -(venv) erikpearson@Eriks-MBP-2 search_api2 % LOGLEVEL=ERROR make integration-tests -Running Integraion Tests... +➤➤ search_api2 (dev-add_workflows) $ make integration-tests +Running Integration Tests... sh scripts/run_integration_tests + path=tests/integration + export PYTHONPATH=. + PYTHONPATH=. -+ poetry run pytest -vv -s tests/integration -=================================================== test session starts =================================================== -platform darwin -- Python 3.7.9, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 -- /Users/erikpearson/work/kbase/sprints/2020Q4/fixes/fix_search_api2_legacy/search_api2/venv/bin/python ++ poetry run pytest -v tests/integration +=========================================================================== test session starts =========================================================================== +platform darwin -- Python 3.9.19, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /Users/sijiex/anaconda3/envs/index/bin/python cachedir: .pytest_cache -rootdir: /Users/erikpearson/work/kbase/sprints/2020Q4/fixes/fix_search_api2_legacy/search_api2 -plugins: cov-2.10.1 -collecting ... Logger and level: - -** To see more or less logging information, adjust the -** log level with the LOGLEVEL environment variable set -** to one of: -** CRITICAL ERROR WARNING INFO DEBUG NOTSET -** It is currently set to: -** ERROR - -collected 9 items - -tests/integration/test_integration_legacy.py::test_search_example1 PASSED -tests/integration/test_integration_legacy.py::test_search_example2 PASSED -tests/integration/test_integration_legacy.py::test_search_example3 PASSED -tests/integration/test_integration_legacy.py::test_search_example4 PASSED -tests/integration/test_integration_legacy.py::test_search_example5 PASSED -tests/integration/test_integration_legacy.py::test_search_example6 PASSED -tests/integration/test_integration_legacy.py::test_search_case1 PASSED -tests/integration/test_integration_search_workspaces.py::test_narrative_example PASSED -tests/integration/test_integration_search_workspaces.py::test_dashboard_example PASSED - -=================================================== 9 passed in 24.27s ==================================================== +rootdir: /Users/sijiex/Documents/LBNL/security/search_api2 +plugins: anyio-4.9.0, cov-2.11.1 +collected 15 items + +tests/integration/test_integration_search_workspaces.py::test_narrative_example PASSED [ 6%] +tests/integration/test_integration_search_workspaces.py::test_dashboard_example PASSED [ 13%] +tests/integration/test_legacy_search_objects.py::test_search_objects_public PASSED [ 20%] +tests/integration/test_legacy_search_objects.py::test_search_example3 PASSED [ 26%] +tests/integration/test_legacy_search_objects.py::test_search_objects_private PASSED [ 33%] +tests/integration/test_legacy_search_objects.py::test_search_objects_multiple_terms_narrow PASSED [ 40%] +tests/integration/test_legacy_search_objects.py::test_search_objects_ PASSED [ 46%] +tests/integration/test_legacy_search_objects.py::test_search_case_01_no_auth PASSED [ 53%] +tests/integration/test_legacy_search_objects.py::test_search_objects_many_results PASSED [ 60%] +tests/integration/test_legacy_search_objects.py::test_search_objects_private_and_public_counts PASSED [ 66%] +tests/integration/test_legacy_search_objects.py::test_search_objects_private_counts PASSED [ 73%] +tests/integration/test_legacy_search_objects.py::test_search_objects_public_counts PASSED [ 80%] +tests/integration/test_legacy_search_objects.py::test_search_objects_neither_private_nor_public PASSED [ 86%] +tests/integration/test_legacy_search_objects.py::test_search_objects_public_vs_private PASSED [ 93%] +tests/integration/test_legacy_search_types.py::test_search_types PASSED [100%] + +====================================================================== 15 passed in 87.24s (0:01:27) ====================================================================== ``` diff --git a/tests/helpers/integration_setup.py b/tests/helpers/integration_setup.py index 0e7da11..b1f22ab 100644 --- a/tests/helpers/integration_setup.py +++ b/tests/helpers/integration_setup.py @@ -1,5 +1,4 @@ import subprocess -import signal from src.utils.wait_for_service import wait_for_service from src.utils.logger import logger import json From 4fd352aa5e5f294107a857668347e81503701914 Mon Sep 17 00:00:00 2001 From: Sijie Date: Tue, 13 May 2025 15:50:43 -0700 Subject: [PATCH 28/37] add readme file for vendored repo --- jsonrpc11base/README.md | 5 +++++ jsonrpcbase/README.md | 5 +++++ tests/integration/test_legacy_search_objects.py | 7 ++++--- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 jsonrpc11base/README.md create mode 100644 jsonrpcbase/README.md diff --git a/jsonrpc11base/README.md b/jsonrpc11base/README.md new file mode 100644 index 0000000..8c9b1e2 --- /dev/null +++ b/jsonrpc11base/README.md @@ -0,0 +1,5 @@ +# jsonrpc11base + +This is a simple JSON-RPC 1.1 library without and agnostic to a transport layer. + +This repository includes a vendored copy of [jsonrpc11base](https://github.com/kbaseincubator/kbase-jsonrpc11base) to resolve dependency conflicts. The original repository was only used by this project, so the code has been brought in directly to simplify maintenance and eliminate external dependency issues. \ No newline at end of file diff --git a/jsonrpcbase/README.md b/jsonrpcbase/README.md new file mode 100644 index 0000000..6086660 --- /dev/null +++ b/jsonrpcbase/README.md @@ -0,0 +1,5 @@ +# jsonrpcbase + +Simple JSON-RPC service without transport layer. + +This repository includes a vendored copy of [jsonrpcbase](https://github.com/kbaseincubator/jsonrpcbase) to resolve dependency conflicts. The original repository was only used by this project, so the code has been brought in directly to simplify maintenance and eliminate external dependency issues. \ No newline at end of file diff --git a/tests/integration/test_legacy_search_objects.py b/tests/integration/test_legacy_search_objects.py index eed2a25..4f277ee 100644 --- a/tests/integration/test_legacy_search_objects.py +++ b/tests/integration/test_legacy_search_objects.py @@ -148,9 +148,10 @@ def get_count(service, with_private, with_public): result = assert_jsonrpc11_result(resp.json(), response_data) return result['total'] -# -# This series of tests relies upon a specific state of data in -# search. + +# NOTE: These tests depend on a specific data state in the search index. +# They query Elasticsearch in the CI environment, and assertions may fail +# if the underlying data has been added, removed, or modified. def test_search_objects_private_and_public_counts(service): From 82bd3359f141f66cce8d56b20a274cf480f54cf9 Mon Sep 17 00:00:00 2001 From: Sijie Date: Thu, 15 May 2025 10:38:05 -0700 Subject: [PATCH 29/37] fix and test containers are correctly shutting downs in both unit and integration tests --- tests/helpers/integration_setup.py | 4 ++-- tests/helpers/unit_setup.py | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/helpers/integration_setup.py b/tests/helpers/integration_setup.py index b1f22ab..f086fef 100644 --- a/tests/helpers/integration_setup.py +++ b/tests/helpers/integration_setup.py @@ -21,7 +21,7 @@ def start_service(app_url): # Build and start the app using docker-compose cwd = 'tests/integration/docker' logger.info(f'Running docker-compose file in "{cwd}"') - cmd = "docker-compose --ansi never up" + cmd = "docker compose --ansi never up" logger.info(f'Running command:\n{cmd}') container_out = open("container.out", "w") container_err = open("container.err", "w") @@ -42,7 +42,7 @@ def stop_service(): # Stop and remove containers cwd = 'tests/integration/docker' - subprocess.run("docker-compose --ansi never down", shell=True, check=True, cwd=cwd) + subprocess.run("docker compose --ansi never down", shell=True, check=True, cwd=cwd) logger.info('Waiting until service has stopped...') diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index ee576af..9470c8f 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -1,5 +1,4 @@ import subprocess -import signal from src.utils.wait_for_service import wait_for_service from src.utils.logger import logger from . import common @@ -26,7 +25,7 @@ def start_service(wait_for_url, wait_for_name): global container_out global container_err - cmd = "docker compose --no-ansi up" + cmd = "docker compose --ansi never up" logger.info(f'Running command:\n{cmd}') container_out = open("container.out", "w") container_err = open("container.err", "w") @@ -41,13 +40,16 @@ def stop_service(): if container_process is not None: logger.info('Stopping container') - container_process.send_signal(signal.SIGTERM) + + # Stop and remove containers + subprocess.run("docker compose --ansi never down", shell=True, check=True) + logger.info('Waiting until service has stopped...') - if not common.wait_for_line("container.err", - lambda line: 'Stopping' in line and 'done' in line, + if not common.wait_for_line("container.out", + lambda line: "exited with code 0" in line, timeout=stop_timeout, line_count=2): - logger.warning(f'Container did not stop in the alotted time of {stop_timeout} seconds') + raise Exception(f'Container did not stop in the alotted time of {stop_timeout} seconds') logger.info('...stopped!') if container_err is not None: From dcd0381a6b626d16250873702869e0d24391bf61 Mon Sep 17 00:00:00 2001 From: Sijie Date: Thu, 15 May 2025 10:53:11 -0700 Subject: [PATCH 30/37] extend stop_timeout --- tests/helpers/unit_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index 9470c8f..2991590 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -9,7 +9,7 @@ container_process = None container_out = None container_err = None -stop_timeout = 30 +stop_timeout = 60 def load_data_file(name): From 8561fe2a5c169f545f6ba221392c98bef959762f Mon Sep 17 00:00:00 2001 From: Sijie Date: Thu, 15 May 2025 15:57:03 -0700 Subject: [PATCH 31/37] add timeout flag --- tests/helpers/unit_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index 2991590..a013bd8 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -9,7 +9,7 @@ container_process = None container_out = None container_err = None -stop_timeout = 60 +stop_timeout = 30 def load_data_file(name): @@ -42,7 +42,7 @@ def stop_service(): logger.info('Stopping container') # Stop and remove containers - subprocess.run("docker compose --ansi never down", shell=True, check=True) + subprocess.run("docker compose --ansi never down --timeout 10", shell=True, check=True) logger.info('Waiting until service has stopped...') if not common.wait_for_line("container.out", From 4044d9e14243f21eb426518c743b26f91538aa10 Mon Sep 17 00:00:00 2001 From: Sijie Date: Thu, 15 May 2025 16:09:03 -0700 Subject: [PATCH 32/37] remove version from docker-compose file and revert back to logger.warning --- docker-compose.yaml | 2 -- tests/helpers/unit_setup.py | 7 +++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 07780c6..e8b4e5e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,3 @@ -version: '3' - # This docker-compose is for developer convenience, not for running in production. services: diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index a013bd8..324738b 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -42,14 +42,17 @@ def stop_service(): logger.info('Stopping container') # Stop and remove containers - subprocess.run("docker compose --ansi never down --timeout 10", shell=True, check=True) + subprocess.run("docker compose --ansi never down", shell=True, check=True) logger.info('Waiting until service has stopped...') if not common.wait_for_line("container.out", lambda line: "exited with code 0" in line, timeout=stop_timeout, line_count=2): - raise Exception(f'Container did not stop in the alotted time of {stop_timeout} seconds') + + # Use logger.warning here to allow tests to pass in CI. + # Note: Containers shut down properly when run locally, but may not behave the same in CI environments. + logger.warning(f'Container did not stop in the alotted time of {stop_timeout} seconds') logger.info('...stopped!') if container_err is not None: From cccb89b36c4aa8b01191ff258aa8eaefd32ec2a0 Mon Sep 17 00:00:00 2001 From: Sijie Date: Thu, 15 May 2025 17:14:43 -0700 Subject: [PATCH 33/37] use kbase-jsonrpcbase 0.3.0a6 and update readme.md file --- jsonrpcbase/README.md | 6 +++++- jsonrpcbase/main.py | 4 +--- tests/unit/search2_rpc/test_search2_rpc.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/jsonrpcbase/README.md b/jsonrpcbase/README.md index 6086660..5552e31 100644 --- a/jsonrpcbase/README.md +++ b/jsonrpcbase/README.md @@ -2,4 +2,8 @@ Simple JSON-RPC service without transport layer. -This repository includes a vendored copy of [jsonrpcbase](https://github.com/kbaseincubator/jsonrpcbase) to resolve dependency conflicts. The original repository was only used by this project, so the code has been brought in directly to simplify maintenance and eliminate external dependency issues. \ No newline at end of file +This repository includes a vendored copy of [jsonrpcbase](https://github.com/kbaseincubator/jsonrpcbase) to resolve dependency conflicts. + +Specifically, this is version kbase-jsonrpcbase 0.3.0a6, extracted from [pypi](https://pypi.org/project/kbase-jsonrpcbase/) + +The original repository was only used by this project, so the code has been brought in directly to simplify maintenance and eliminate external dependency issues. \ No newline at end of file diff --git a/jsonrpcbase/main.py b/jsonrpcbase/main.py index cf97556..664e545 100644 --- a/jsonrpcbase/main.py +++ b/jsonrpcbase/main.py @@ -55,8 +55,6 @@ -32603: 'Internal error', # Reserved for implementation-defined server-errors. -32000: 'Server error', - # Elasticsearch response error - -32003: 'Elasticsearch response error', } log = logging.getLogger(__name__) @@ -294,7 +292,7 @@ def _err_response(self, 'id': _id, 'error': { 'code': code, - 'message': RPC_ERRORS[code], + 'message': RPC_ERRORS.get(code, 'Server error'), } } if err_data: diff --git a/tests/unit/search2_rpc/test_search2_rpc.py b/tests/unit/search2_rpc/test_search2_rpc.py index 53241ad..41c68ff 100644 --- a/tests/unit/search2_rpc/test_search2_rpc.py +++ b/tests/unit/search2_rpc/test_search2_rpc.py @@ -50,7 +50,7 @@ def test_show_indexes_error(services): res = json.loads(result) assert res['error'] assert res['error']['code'] == -32003 - assert res['error']['message'] == 'Elasticsearch response error' + assert res['error']['message'] == 'Server error' assert res['error']['data']['method'] == 'show_indexes' From 542b9dccdc88c8584b41bb1a0313227e1a88f807 Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 16 May 2025 14:36:38 -0700 Subject: [PATCH 34/37] update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01c5984..2f74a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Standard GitHub Actions workflows + +### Changed +- Upgraded Python to version 3.9.19 in test workflows and Dockerfile +- Updated integration tests README file + +### Fixed +- Container/service shutdown issues; all unit and integration tests now pass locally + +### Security +- Vendored `kbase-jsonrpcbase` 0.3.0a6 and `jsonrpc11base` to resolve dependency conflicts ## [1.0.0] - 2021-04-20 ### Fixed From 623dad43a2eab8413e2aeedcbb3e4dc5aacbf6b9 Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 16 May 2025 16:52:37 -0700 Subject: [PATCH 35/37] update jsonrpc readme.md file --- jsonrpcbase/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsonrpcbase/README.md b/jsonrpcbase/README.md index 5552e31..6ea36a6 100644 --- a/jsonrpcbase/README.md +++ b/jsonrpcbase/README.md @@ -2,8 +2,8 @@ Simple JSON-RPC service without transport layer. -This repository includes a vendored copy of [jsonrpcbase](https://github.com/kbaseincubator/jsonrpcbase) to resolve dependency conflicts. +This repository includes a vendored copy of [jsonrpcbase](https://pypi.org/project/kbase-jsonrpcbase/) version `0.3.0a6` to resolve dependency conflicts. -Specifically, this is version kbase-jsonrpcbase 0.3.0a6, extracted from [pypi](https://pypi.org/project/kbase-jsonrpcbase/) +Note that there exists a [github repo](https://github.com/kbaseincubator/jsonrpcbase) which is presumably the source of the PyPi module, but it appears to only contain the alpha5 release of the code vs. PyPi's alpha6. It is not clear where the alpha6 code resides other than PyPi. The original repository was only used by this project, so the code has been brought in directly to simplify maintenance and eliminate external dependency issues. \ No newline at end of file From 8cf55e59879a055756b087cd0598b16b1c822616 Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 16 May 2025 17:17:14 -0700 Subject: [PATCH 36/37] clean up stop_serivce function --- tests/helpers/integration_setup.py | 10 +--------- tests/helpers/unit_setup.py | 12 +----------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/tests/helpers/integration_setup.py b/tests/helpers/integration_setup.py index f086fef..ad623d3 100644 --- a/tests/helpers/integration_setup.py +++ b/tests/helpers/integration_setup.py @@ -43,15 +43,7 @@ def stop_service(): # Stop and remove containers cwd = 'tests/integration/docker' subprocess.run("docker compose --ansi never down", shell=True, check=True, cwd=cwd) - - logger.info('Waiting until service has stopped...') - - if not common.wait_for_line("container.out", - lambda line: "exited with code 0" in line, - timeout=stop_timeout, - line_count=1): - raise Exception(f'Container did not stop in the alloted time of {stop_timeout} seconds') - logger.info('...stopped!') + logger.info('Service has stopped!') if container_err is not None: container_err.close() diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index 324738b..cbda82f 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -43,17 +43,7 @@ def stop_service(): # Stop and remove containers subprocess.run("docker compose --ansi never down", shell=True, check=True) - - logger.info('Waiting until service has stopped...') - if not common.wait_for_line("container.out", - lambda line: "exited with code 0" in line, - timeout=stop_timeout, - line_count=2): - - # Use logger.warning here to allow tests to pass in CI. - # Note: Containers shut down properly when run locally, but may not behave the same in CI environments. - logger.warning(f'Container did not stop in the alotted time of {stop_timeout} seconds') - logger.info('...stopped!') + logger.info('Service has stopped!') if container_err is not None: container_err.close() From efa12c86ebb824983b7e5a4cd2ced4a228080531 Mon Sep 17 00:00:00 2001 From: Sijie Date: Fri, 16 May 2025 17:50:51 -0700 Subject: [PATCH 37/37] remove unused dep --- tests/helpers/integration_setup.py | 1 - tests/helpers/unit_setup.py | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/helpers/integration_setup.py b/tests/helpers/integration_setup.py index ad623d3..81b888e 100644 --- a/tests/helpers/integration_setup.py +++ b/tests/helpers/integration_setup.py @@ -4,7 +4,6 @@ import json import os import requests -from . import common from .common import assert_jsonrpc11_result, equal container_process = None diff --git a/tests/helpers/unit_setup.py b/tests/helpers/unit_setup.py index cbda82f..c82b37e 100644 --- a/tests/helpers/unit_setup.py +++ b/tests/helpers/unit_setup.py @@ -1,7 +1,6 @@ import subprocess from src.utils.wait_for_service import wait_for_service from src.utils.logger import logger -from . import common import json import os