diff --git a/.github/actions/kserve-dep-setup/action.yml b/.github/actions/kserve-dep-setup/action.yml index 37a08dd830f..e01c200a837 100644 --- a/.github/actions/kserve-dep-setup/action.yml +++ b/.github/actions/kserve-dep-setup/action.yml @@ -17,22 +17,14 @@ runs: run: | shopt -s nocasematch - if [[ "${{ inputs.network-layer }}" == "istio" ]]; then - echo "Selected network layer ${{ inputs.network-layer }}" - ./test/scripts/gh-actions/setup-deps.sh ${{ inputs.deployment-mode }} - - kubectl get pods -n istio-system - kubectl describe svc -n istio-system istio-ingressgateway - elif [[ "${{ inputs.network-layer }}" == "kourier" ]]; then - echo "Selected network layer ${{ inputs.network-layer }}" - ./test/scripts/gh-actions/setup-kourier.sh + if [[ "${{ inputs.network-layer }}" == "kourier" ]]; then + echo "Selected network layer ${{ inputs.network-layer }}" + ./test/scripts/gh-actions/setup-kourier.sh else - echo "Unsupported network layer" + echo "Selected network layer ${{ inputs.network-layer }}" + ./test/scripts/gh-actions/setup-deps.sh ${{ inputs.deployment-mode }} "${{ inputs.network-layer }}" fi - kubectl get pods -n knative-serving - kubectl get pods -n cert-manager - - name: Update test overlays shell: bash run: | diff --git a/.github/actions/minikube-setup/action.yml b/.github/actions/minikube-setup/action.yml index 5788a4f022a..188375b251e 100644 --- a/.github/actions/minikube-setup/action.yml +++ b/.github/actions/minikube-setup/action.yml @@ -1,22 +1,38 @@ name: 'Minikube setup action' description: 'Sets up minikube on the github runner' +inputs: + nodes: + description: 'Number of nodes to start minikube with' + required: false + default: '1' + driver: + description: 'Driver to use for minikube' + required: false + default: 'none' + start-args: + description: 'Additional arguments to pass to minikube start' + required: false + default: '' + runs: using: "composite" steps: - name: Install kubectl uses: azure/setup-kubectl@v4.0.0 with: - version: 'v1.29.7' + version: 'v1.30.7' - name: Setup Minikube uses: medyagh/setup-minikube@latest with: minikube-version: '1.33.1' - kubernetes-version: 'v1.29.7' - driver: 'none' + kubernetes-version: 'v1.30.7' + driver: ${{ inputs.driver }} wait: 'all' - start-args: --wait-timeout=6m0s + cpus: 'max' + memory: 'max' + start-args: --wait-timeout=6m0s --nodes=${{ inputs.nodes }} ${{ inputs.start-args }} - name: Check Kubernetes pods shell: bash diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 855eb7ea3be..2530cf03bfc 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -24,6 +24,7 @@ env: # Controller images CONTROLLER_IMG: "kserve-controller" LOCALMODEL_CONTROLLER_IMG: "kserve-localmodel-controller" + LOCALMODEL_AGENT_IMG: "kserve-localmodelnode-agent" STORAGE_INIT_IMG: "storage-initializer" AGENT_IMG: "agent" ROUTER_IMG: "router" @@ -87,6 +88,14 @@ jobs: compression-level: 0 if-no-files-found: error + - name: Upload localmodel agent image + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASE_ARTIFACT_PREFIX }}-${{ env.LOCALMODEL_AGENT_IMG }}-${{ github.sha }} + path: ${{ env.DOCKER_IMAGES_PATH }}/${{ env.LOCALMODEL_AGENT_IMG }}-${{ github.sha }} + compression-level: 0 + if-no-files-found: error + - name: Upload agent image uses: actions/upload-artifact@v4 with: @@ -589,7 +598,7 @@ jobs: - name: Patch inferenceservice config run: | - kubectl patch configmaps -n kserve inferenceservice-config --patch-file config/overlays/test/configmap/inferenceservice-ingress.yaml + kubectl patch configmaps -n kserve inferenceservice-config --patch-file config/overlays/test/configmap/inferenceservice-path-template.yaml kubectl describe configmaps -n kserve inferenceservice-config - name: Run E2E tests with path-based routing @@ -720,8 +729,13 @@ jobs: test-raw: runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + # Test with Ingress and Gateway API + network-layer: ["istio-ingress", "envoy-gatewayapi", "istio-gatewayapi"] needs: - [kserve-image-build, predictor-runtime-build] + [kserve-image-build, predictor-runtime-build, explainer-runtime-build] steps: - name: Checkout source uses: actions/checkout@v4 @@ -733,6 +747,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: "1.22" + - name: Setup Python uses: actions/setup-python@v5 with: @@ -745,6 +760,7 @@ jobs: uses: ./.github/actions/kserve-dep-setup with: deployment-mode: "raw" + network-layer: ${{ matrix.network-layer }} - name: Download base images uses: ./.github/actions/base-download @@ -767,11 +783,12 @@ jobs: name: ${{ env.PREDICTOR_ARTIFACT_PREFIX }}-${{ env.CUSTOM_MODEL_GRPC_IMG }}-${{ github.sha }} path: ./tmp - - name: Download transformer image + - name: Download transformer and explainer artifacts uses: actions/download-artifact@v4 with: - name: ${{ env.TRANSFORMER_ARTIFACT_PREFIX }}-${{ env.IMAGE_TRANSFORMER_IMG }}-${{ github.sha }} path: ./tmp + pattern: +(${{ env.TRANSFORMER_ARTIFACT_PREFIX }}|${{ env.EXPLAINER_ARTIFACT_PREFIX }})-* + merge-multiple: true - name: Load docker images uses: ./.github/actions/load-docker-images @@ -783,7 +800,7 @@ jobs: - name: Install KServe run: | - ./test/scripts/gh-actions/setup-kserve.sh "raw" + ./test/scripts/gh-actions/setup-kserve.sh "raw" ${{ matrix.network-layer }} kubectl get pods -n kserve kubectl describe pods -n kserve @@ -792,10 +809,27 @@ jobs: run: | kubectl describe configmaps -n kserve inferenceservice-config + - name: Enable Gateway API + if: matrix.network-layer == 'envoy-gatewayapi' || matrix.network-layer == 'istio-gatewayapi' + run: | + kubectl patch configmaps -n kserve inferenceservice-config --patch-file config/overlays/test/configmap/inferenceservice-enable-gateway-api.yaml + - name: Run E2E tests timeout-minutes: 30 run: | - ./test/scripts/gh-actions/run-e2e-tests.sh "raw" "6" + ./test/scripts/gh-actions/run-e2e-tests.sh "raw" "6" ${{ matrix.network-layer }} + + - name: Patch inferenceservice config for path based routing + if: matrix.network-layer == 'envoy-gatewayapi' || matrix.network-layer == 'istio-gatewayapi' + run: | + kubectl patch configmaps -n kserve inferenceservice-config --patch-file config/overlays/test/configmap/inferenceservice-path-template.yaml + kubectl describe configmaps -n kserve inferenceservice-config + + - name: Run E2E tests with path based routing + if: matrix.network-layer == 'envoy-gatewayapi' || matrix.network-layer == 'istio-gatewayapi' + timeout-minutes: 30 + run: | + ./test/scripts/gh-actions/run-e2e-tests.sh "raw" "6" ${{ matrix.network-layer }} - name: Patch inferenceservice config for cluster ip none run: | @@ -805,7 +839,7 @@ jobs: - name: Run E2E tests - cluster ip none timeout-minutes: 30 run: | - ./test/scripts/gh-actions/run-e2e-tests.sh "rawcipn" "1" + ./test/scripts/gh-actions/run-e2e-tests.sh "rawcipn" "1" ${{ matrix.network-layer }} - name: Check system status if: always() @@ -900,7 +934,7 @@ jobs: test-llm: runs-on: ubuntu-22.04 needs: - [ kserve-image-build, predictor-runtime-build] + [kserve-image-build, predictor-runtime-build] steps: - name: Checkout source uses: actions/checkout@v4 @@ -960,7 +994,7 @@ jobs: test-huggingface-server-vllm: runs-on: ubuntu-22.04 needs: - [ kserve-image-build, predictor-runtime-build] + [kserve-image-build, predictor-runtime-build] steps: - name: Checkout source uses: actions/checkout@v4 @@ -1015,4 +1049,129 @@ jobs: - name: Check system status if: always() run: | + ./test/scripts/gh-actions/status-check.sh + + test-modelcache: + runs-on: ubuntu-22.04 + needs: + [kserve-image-build, predictor-runtime-build] + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Free-up disk space + uses: ./.github/actions/free-up-disk-space + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Create tmp-images directory + run: | + sudo mkdir -p /tmp-images + sudo chown -R $USER /tmp-images + + - name: Setup Minikube + uses: ./.github/actions/minikube-setup + with: + nodes: 3 + driver: "docker" + start-args: "--mount --mount-string=/tmp-images:/tmp-images" + + - name: Create minikube tunnel + run: | + nohup minikube tunnel > minikube-tunnel.log 2>&1 & + + - name: KServe dependency setup + uses: ./.github/actions/kserve-dep-setup + + - name: Download base images + uses: actions/download-artifact@v4 + with: + path: /tmp-images + pattern: ${{ env.BASE_ARTIFACT_PREFIX }}-* + merge-multiple: true + + - name: Load base docker images + run: | + ls -l /tmp-images + minikube ssh -n minikube -- ls -l /tmp-images + files=$(find /tmp-images -maxdepth 1 -type f) + for file in ${files[@]};do + echo "Loading image $(basename ${file})" + minikube ssh -n minikube -- docker image load -i ${file} + minikube ssh -n minikube-m02 -- docker image load -i ${file} + minikube ssh -n minikube-m03 -- docker image load -i ${file} + done + sudo rm -rf /tmp-images/* + minikube ssh -n minikube -- docker image ls + minikube ssh -n minikube-m02 -- docker image ls + minikube ssh -n minikube-m03 -- docker image ls + + - name: Download huggingface server image + uses: actions/download-artifact@v4 + with: + name: ${{ env.HUGGINGFACE_IMG }}-${{ github.sha }} + path: /tmp-images + + - name: Load runtime docker images + run: | + files=$(find /tmp-images -maxdepth 1 -type f) + for file in ${files[@]};do + echo "Loading image $(basename ${file})" + minikube ssh -n minikube-m02 -- docker image load -i ${file} + done + sudo rm -rf tmp-images/* + minikube ssh -n minikube-m02 -- docker image ls + + - name: Create model root directory + run: | + minikube ssh -n minikube-m02 -- sudo mkdir -p -m=777 /models + minikube ssh -n minikube-m03 -- sudo mkdir -p -m=777 /models + + - name: Install Poetry and version plugin + run: ./test/scripts/gh-actions/setup-poetry.sh + + - name: Install KServe + run: | + ./test/scripts/gh-actions/setup-kserve.sh + + kubectl get pods -n kserve + kubectl describe pods -n kserve + + - name: Enable modelcache + run: | + sed -i -e "s/latest/${GITHUB_SHA}/g" config/overlays/test/configmap/inferenceservice-enable-modelcache.yaml + kubectl patch configmaps -n kserve inferenceservice-config --patch-file config/overlays/test/configmap/inferenceservice-enable-modelcache.yaml + kubectl describe configmaps -n kserve inferenceservice-config + + - name: Create localmodel job namespace + run: | + kubectl create ns kserve-localmodel-jobs + + - name: Label worker nodes for modelcache + run: | + kubectl label nodes -l '!node-role.kubernetes.io/control-plane' kserve/localmodel=worker + + - name: Enable nodeselector in knative + run: | + kubectl patch configmaps -n knative-serving config-features --patch '{"data": {"kubernetes.podspec-nodeselector": "enabled"}}' + + - name: Run E2E tests + timeout-minutes: 15 + run: | + ./test/scripts/gh-actions/run-e2e-tests.sh "modelcache" "1" + + - name: Check system status + if: always() + run: | + echo "::group::Minikube tunnel logs" + cat minikube-tunnel.log + echo "::endgroup::" ./test/scripts/gh-actions/status-check.sh \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index f44d41359b8..ea62bbbe51a 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: "1.22" cache: false - name: golangci-lint uses: golangci/golangci-lint-action@v4 @@ -26,3 +26,39 @@ jobs: version: v1.56 args: --out-format=line-number + verify-go-mod: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.22 + cache: false + + - name: Run go mod tidy + run: | + go mod tidy + + - name: Verify + shell: bash + run: | + # From: https://backreference.org/2009/12/23/how-to-match-newlines-in-sed/ + # This is to leverage this workaround: + # https://github.com/actions/toolkit/issues/193#issuecomment-605394935 + urlencode() { + sed ':begin;$!N;s/\n/%0A/;tbegin' + } + + if [ -z "$(git status --porcelain)" ]; then + echo "${{ github.repository }} up to date." + else + echo "Found diffs in: $(git diff-index --name-only HEAD)" + for x in $(git diff-index --name-only HEAD); do + echo "::error file=$x::Please run 'go mod tidy'.%0A$(git diff $x | urlencode)" + done + echo "${{ github.repository }} is out of date. Please run 'go mod tidy'" + exit 1 + fi diff --git a/.github/workflows/huggingface-vllm-docker-publish-manual.yml b/.github/workflows/huggingface-vllm-docker-publish-manual.yml new file mode 100644 index 00000000000..2255e5a0bd6 --- /dev/null +++ b/.github/workflows/huggingface-vllm-docker-publish-manual.yml @@ -0,0 +1,70 @@ +name: Huggingface vLLM Docker Publisher + +on: + workflow_dispatch: + inputs: + version: + description: 'Huggingface vLLM image version to publish' + required: true + +env: + IMAGE_NAME: huggingfaceserver + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + push: + strategy: + fail-fast: false + matrix: + image: + - version: ${{ inputs.version }} + path: 'python/huggingface_server_cpu_openvino.Dockerfile' + - version: ${{ inputs.version }}-gpu + path: 'python/huggingface_server.Dockerfile' + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Free-up disk space + uses: ./.github/actions/free-up-disk-space + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Export image id and version variable + run: | + IMAGE_ID=kserve/$IMAGE_NAME + + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + + # Add prefix v to version if it doesn't start with v + if [[ ${{ matrix.image.version }} != v* ]]; then + VERSION="v${{ matrix.image.version }}" + else + VERSION="${{ matrix.image.version }}" + fi + + echo IMAGE_ID=$IMAGE_ID >> $GITHUB_ENV + echo VERSION=$VERSION >> $GITHUB_ENV + + - name: Build and push + uses: docker/build-push-action@v5 + with: + platforms: linux/amd64 + context: python + file: ${{ matrix.image.path }} + push: true + tags: ${{ env.IMAGE_ID }}:${{ env.VERSION }} + # https://github.com/docker/buildx/issues/1533 + provenance: false diff --git a/.github/workflows/kserve-localmodel-agent-docker-publish.yml b/.github/workflows/kserve-localmodel-agent-docker-publish.yml new file mode 100644 index 00000000000..9b09350efdb --- /dev/null +++ b/.github/workflows/kserve-localmodel-agent-docker-publish.yml @@ -0,0 +1,95 @@ +name: Kserve localmodel agent Docker Publisher + +on: + push: + # Publish `master` as Docker `latest` image. + branches: + - master + + # Publish `v1.2.3` tags as releases. + tags: + - v* + + # Run tests for any PRs. + pull_request: + +env: + IMAGE_NAME: kserve-localmodelnode-agent + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Run tests. + # See also https://docs.docker.com/docker-hub/builds/automated-testing/ + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Run tests + run: | + if [ -f docker-compose.test.yml ]; then + docker-compose --file docker-compose.test.yml build + docker-compose --file docker-compose.test.yml run sut + else + docker buildx build . --file localmodel-agent.Dockerfile + fi + + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + push: + # Ensure test job passes before pushing image. + needs: test + + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: export version variable + run: | + IMAGE_ID=kserve/$IMAGE_NAME + + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + + # Strip git ref prefix from version + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + + # Strip "v" prefix from tag name + # [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + + # Use Docker `latest` tag convention + [ "$VERSION" == "master" ] && VERSION=latest + + echo VERSION=$VERSION >> $GITHUB_ENV + echo IMAGE_ID=$IMAGE_ID >> $GITHUB_ENV + + - name: Build and push + uses: docker/build-push-action@v5 + with: + platforms: linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + context: . + file: localmodel-agent.Dockerfile + push: true + tags: ${{ env.IMAGE_ID }}:${{ env.VERSION }} + # https://github.com/docker/buildx/issues/1533 + provenance: false diff --git a/.github/workflows/scheduled-image-scan.yml b/.github/workflows/scheduled-image-scan.yml index 721baecd63d..83385d4a5ce 100644 --- a/.github/workflows/scheduled-image-scan.yml +++ b/.github/workflows/scheduled-image-scan.yml @@ -19,12 +19,10 @@ jobs: [ { name: kserve-controller, file: Dockerfile }, { name: agent, file: agent.Dockerfile }, - { - name: storage-initializer, - file: python/storage-initializer.Dockerfile, - }, + { name: storage-initializer, file: python/storage-initializer.Dockerfile }, { name: router, file: router.Dockerfile }, { name: kserve-localmodel-controller, file: localmodel.Dockerfile }, + { name: kserve-localmodelnode-agent, file: localmodel-agent.Dockerfile }, ] steps: @@ -112,10 +110,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - image: - [ - { name: art-explainer, file: python/artexplainer.Dockerfile }, - ] + image: [{ name: art-explainer, file: python/artexplainer.Dockerfile }] steps: - name: Checkout diff --git a/Makefile b/Makefile index 9e117a98a73..81ccadbe230 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ CUSTOM_MODEL_GRPC_IMG ?= custom-model-grpc CUSTOM_TRANSFORMER_IMG ?= image-transformer CUSTOM_TRANSFORMER_GRPC_IMG ?= custom-image-transformer-grpc HUGGINGFACE_SERVER_IMG ?= huggingfaceserver +HUGGINGFACE_SERVER_CPU_IMG ?= huggingfaceserver-cpu-openvino AIF_IMG ?= aiffairness ART_IMG ?= art-explainer STORAGE_INIT_IMG ?= storage-initializer @@ -28,6 +29,12 @@ ENVTEST_K8S_VERSION = 1.29 SUCCESS_200_ISVC_IMG ?= success-200-isvc ERROR_404_ISVC_IMG ?= error-404-isvc +ENGINE ?= docker +# Empty string for local build when using podman, it allows to build different architectures +# to use do: ENGINE=podman ARCH="--arch x86_64" make docker-build-something +ARCH ?= + + ## Location to install dependencies to LOCALBIN ?= $(shell pwd)/bin $(LOCALBIN): @@ -91,7 +98,7 @@ deploy-dev: manifests if [ ${KSERVE_ENABLE_SELF_SIGNED_CA} != false ]; then ./hack/self-signed-ca.sh; fi; # TODO: Add runtimes as part of default deployment kubectl wait --for=condition=ready pod -l control-plane=kserve-controller-manager -n kserve --timeout=300s - kubectl apply --server-side=true -k config/clusterresources + kubectl apply --server-side=true --force-conflicts -k config/clusterresources git checkout HEAD -- config/certmanager/certificate.yaml deploy-dev-sklearn: docker-push-sklearn @@ -124,7 +131,7 @@ deploy-ci: manifests deploy-helm: manifests helm install kserve-crd charts/kserve-crd/ --wait --timeout 180s - helm install kserve charts/kserve-resources/ --wait --timeout 180s + helm install kserve charts/kserve-resources/ --wait --timeout 180s -n kserve --create-namespace undeploy: kubectl delete -k config/default @@ -207,8 +214,8 @@ bump-version: @hack/prepare-for-release.sh $(PRIOR_VERSION) $(NEW_VERSION) # Build the docker image -docker-build: test - docker buildx build . -t ${IMG} +docker-build: + ${ENGINE} buildx build ${ARCH} . -t ${IMG} @echo "updating kustomize image patch file for manager resource" # Use perl instead of sed to avoid OSX/Linux compatibility issue: @@ -220,115 +227,121 @@ docker-push: docker push ${IMG} docker-build-agent: - docker buildx build -f agent.Dockerfile . -t ${KO_DOCKER_REPO}/${AGENT_IMG} + ${ENGINE} buildx build ${ARCH} -f agent.Dockerfile . -t ${KO_DOCKER_REPO}/${AGENT_IMG} docker-build-router: - docker buildx build -f router.Dockerfile . -t ${KO_DOCKER_REPO}/${ROUTER_IMG} + ${ENGINE} buildx build ${ARCH} -f router.Dockerfile . -t ${KO_DOCKER_REPO}/${ROUTER_IMG} docker-push-agent: - docker push ${KO_DOCKER_REPO}/${AGENT_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${AGENT_IMG} docker-push-router: - docker push ${KO_DOCKER_REPO}/${ROUTER_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${ROUTER_IMG} docker-build-sklearn: - cd python && docker buildx build --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${SKLEARN_IMG} -f sklearn.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${SKLEARN_IMG} -f sklearn.Dockerfile . docker-push-sklearn: docker-build-sklearn - docker push ${KO_DOCKER_REPO}/${SKLEARN_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${SKLEARN_IMG} docker-build-xgb: - cd python && docker buildx build --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${XGB_IMG} -f xgb.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${XGB_IMG} -f xgb.Dockerfile . docker-push-xgb: docker-build-xgb - docker push ${KO_DOCKER_REPO}/${XGB_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${XGB_IMG} docker-build-lgb: - cd python && docker buildx build --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${LGB_IMG} -f lgb.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${LGB_IMG} -f lgb.Dockerfile . docker-push-lgb: docker-build-lgb - docker push ${KO_DOCKER_REPO}/${LGB_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${LGB_IMG} docker-build-pmml: - cd python && docker buildx build --build-arg BASE_IMAGE=${PMML_BASE_IMG} -t ${KO_DOCKER_REPO}/${PMML_IMG} -f pmml.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${PMML_BASE_IMG} -t ${KO_DOCKER_REPO}/${PMML_IMG} -f pmml.Dockerfile . docker-push-pmml: docker-build-pmml - docker push ${KO_DOCKER_REPO}/${PMML_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${PMML_IMG} docker-build-paddle: - cd python && docker buildx build --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${PADDLE_IMG} -f paddle.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${PADDLE_IMG} -f paddle.Dockerfile . docker-push-paddle: docker-build-paddle - docker push ${KO_DOCKER_REPO}/${PADDLE_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${PADDLE_IMG} docker-build-custom-model: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${CUSTOM_MODEL_IMG} -f custom_model.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${CUSTOM_MODEL_IMG} -f custom_model.Dockerfile . docker-push-custom-model: docker-build-custom-model docker push ${KO_DOCKER_REPO}/${CUSTOM_MODEL_IMG} docker-build-custom-model-grpc: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${CUSTOM_MODEL_GRPC_IMG} -f custom_model_grpc.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${CUSTOM_MODEL_GRPC_IMG} -f custom_model_grpc.Dockerfile . docker-push-custom-model-grpc: docker-build-custom-model-grpc - docker push ${KO_DOCKER_REPO}/${CUSTOM_MODEL_GRPC_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${CUSTOM_MODEL_GRPC_IMG} docker-build-custom-transformer: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_IMG} -f custom_transformer.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_IMG} -f custom_transformer.Dockerfile . docker-push-custom-transformer: docker-build-custom-transformer - docker push ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_IMG} docker-build-custom-transformer-grpc: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_GRPC_IMG} -f custom_transformer_grpc.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_GRPC_IMG} -f custom_transformer_grpc.Dockerfile . docker-push-custom-transformer-grpc: docker-build-custom-transformer-grpc - docker push ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_GRPC_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${CUSTOM_TRANSFORMER_GRPC_IMG} docker-build-aif: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${AIF_IMG} -f aiffairness.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${AIF_IMG} -f aiffairness.Dockerfile . docker-push-aif: docker-build-aif - docker push ${KO_DOCKER_REPO}/${AIF_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${AIF_IMG} docker-build-art: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${ART_IMG} -f artexplainer.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${ART_IMG} -f artexplainer.Dockerfile . docker-push-art: docker-build-art - docker push ${KO_DOCKER_REPO}/${ART_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${ART_IMG} docker-build-storageInitializer: - cd python && docker buildx build --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${STORAGE_INIT_IMG} -f storage-initializer.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} --build-arg BASE_IMAGE=${BASE_IMG} -t ${KO_DOCKER_REPO}/${STORAGE_INIT_IMG} -f storage-initializer.Dockerfile . docker-push-storageInitializer: docker-build-storageInitializer - docker push ${KO_DOCKER_REPO}/${STORAGE_INIT_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${STORAGE_INIT_IMG} docker-build-qpext: - docker buildx build -t ${KO_DOCKER_REPO}/${QPEXT_IMG} -f qpext/qpext.Dockerfile . + ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${QPEXT_IMG} -f qpext/qpext.Dockerfile . docker-build-push-qpext: docker-build-qpext - docker push ${KO_DOCKER_REPO}/${QPEXT_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${QPEXT_IMG} deploy-dev-qpext: docker-build-push-qpext kubectl patch cm config-deployment -n knative-serving --type merge --patch '{"data": {"queue-sidecar-image": "${KO_DOCKER_REPO}/${QPEXT_IMG}"}}' docker-build-success-200-isvc: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${SUCCESS_200_ISVC_IMG} -f success_200_isvc.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${SUCCESS_200_ISVC_IMG} -f success_200_isvc.Dockerfile . docker-push-success-200-isvc: docker-build-success-200-isvc - docker push ${KO_DOCKER_REPO}/${SUCCESS_200_ISVC_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${SUCCESS_200_ISVC_IMG} docker-build-error-node-404: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${ERROR_404_ISVC_IMG} -f error_404_isvc.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${ERROR_404_ISVC_IMG} -f error_404_isvc.Dockerfile . docker-push-error-node-404: docker-build-error-node-404 - docker push ${KO_DOCKER_REPO}/${ERROR_404_ISVC_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${ERROR_404_ISVC_IMG} docker-build-huggingface: - cd python && docker buildx build -t ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_IMG} -f huggingface_server.Dockerfile . + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_IMG} -f huggingface_server.Dockerfile . docker-push-huggingface: docker-build-huggingface - docker push ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_IMG} + ${ENGINE} push ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_IMG} + +docker-build-huggingface-cpu-openvino: + cd python && ${ENGINE} buildx build ${ARCH} -t ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_CPU_IMG} -f huggingface_server_cpu_openvino.Dockerfile . + +docker-push-huggingface-cpu-openvino: docker-build-huggingface-cpu-openvino + ${ENGINE} push ${KO_DOCKER_REPO}/${HUGGINGFACE_SERVER_CPU_IMG} test-qpext: cd qpext && go test -v ./... -cover @@ -342,8 +355,8 @@ $(ENVTEST): $(LOCALBIN) test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest apidocs: - docker buildx build -f docs/apis/Dockerfile --rm -t apidocs-gen . && \ - docker run -it --rm -v $(CURDIR)/pkg/apis:/go/src/github.com/kserve/kserve/pkg/apis -v ${PWD}/docs/apis:/go/gen-crd-api-reference-docs/apidocs apidocs-gen + ${ENGINE} buildx build ${ARCH} -f docs/apis/Dockerfile --rm -t apidocs-gen . && \ + ${ENGINE} run -it --rm -v $(CURDIR)/pkg/apis:/go/src/github.com/kserve/kserve/pkg/apis -v ${PWD}/docs/apis:/go/gen-crd-api-reference-docs/apidocs apidocs-gen .PHONY: check-doc-links check-doc-links: diff --git a/charts/kserve-crd-minimal/Chart.yaml b/charts/kserve-crd-minimal/Chart.yaml index b37614f6cd0..5f9396b8642 100644 --- a/charts/kserve-crd-minimal/Chart.yaml +++ b/charts/kserve-crd-minimal/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: kserve-crd-minimal -version: v0.14.0 +version: v0.15.0-rc0 description: Helm chart for deploying minimal kserve crds without validation keywords: - kserve diff --git a/charts/kserve-crd-minimal/README.md b/charts/kserve-crd-minimal/README.md index 23304d071bf..0319f65affc 100644 --- a/charts/kserve-crd-minimal/README.md +++ b/charts/kserve-crd-minimal/README.md @@ -2,12 +2,12 @@ Helm chart for deploying minimal kserve crds without validation -![Version: v0.14.0](https://img.shields.io/badge/Version-v0.14.0-informational?style=flat-square) +![Version: v0.15.0-rc0](https://img.shields.io/badge/Version-v0.15.0--rc0-informational?style=flat-square) ## Installing the Chart To install the chart, run the following: ```console -$ helm install kserve-crd-minimal oci://ghcr.io/kserve/charts/kserve-crd-minimal --version v0.14.0 +$ helm install kserve-crd-minimal oci://ghcr.io/kserve/charts/kserve-crd-minimal --version v0.15.0-rc0 ``` diff --git a/charts/kserve-crd/Chart.yaml b/charts/kserve-crd/Chart.yaml index 71d9775854e..9649e3a3064 100644 --- a/charts/kserve-crd/Chart.yaml +++ b/charts/kserve-crd/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: kserve-crd -version: v0.14.0 +version: v0.15.0-rc0 description: Helm chart for deploying kserve crds keywords: - kserve diff --git a/charts/kserve-crd/README.md b/charts/kserve-crd/README.md index e5d31378d0a..4d52dde8e22 100644 --- a/charts/kserve-crd/README.md +++ b/charts/kserve-crd/README.md @@ -2,12 +2,12 @@ Helm chart for deploying kserve crds -![Version: v0.14.0](https://img.shields.io/badge/Version-v0.14.0-informational?style=flat-square) +![Version: v0.15.0-rc0](https://img.shields.io/badge/Version-v0.15.0--rc0-informational?style=flat-square) ## Installing the Chart To install the chart, run the following: ```console -$ helm install kserve-crd oci://ghcr.io/kserve/charts/kserve-crd --version v0.14.0 +$ helm install kserve-crd oci://ghcr.io/kserve/charts/kserve-crd --version v0.15.0-rc0 ``` diff --git a/charts/kserve-crd/templates/serving.kserve.io_clusterservingruntimes.yaml b/charts/kserve-crd/templates/serving.kserve.io_clusterservingruntimes.yaml index 4a9079784b4..743e43f67ea 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_clusterservingruntimes.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_clusterservingruntimes.yaml @@ -1001,6 +1001,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1335,10 +1337,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -1698,6 +1702,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -1711,6 +1722,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -1959,6 +1971,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -1966,6 +1979,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -1977,6 +1991,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -1985,6 +2000,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -2002,6 +2018,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -2963,6 +2980,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -3217,7 +3236,9 @@ spec: additionalProperties: type: string type: object - size: + pipelineParallelSize: + type: integer + tensorParallelSize: type: integer tolerations: items: @@ -3261,10 +3282,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3624,6 +3647,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3637,6 +3667,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3885,6 +3916,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3892,6 +3924,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3903,6 +3936,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3911,6 +3945,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3928,6 +3963,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/charts/kserve-crd/templates/serving.kserve.io_clusterstoragecontainers.yaml b/charts/kserve-crd/templates/serving.kserve.io_clusterstoragecontainers.yaml index 0afee25e8c3..944ed597fce 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_clusterstoragecontainers.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_clusterstoragecontainers.yaml @@ -469,6 +469,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object diff --git a/charts/kserve-crd/templates/serving.kserve.io_inferencegraphs.yaml b/charts/kserve-crd/templates/serving.kserve.io_inferencegraphs.yaml index d14444c8486..b83542ae233 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_inferencegraphs.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_inferencegraphs.yaml @@ -526,6 +526,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object diff --git a/charts/kserve-crd/templates/serving.kserve.io_inferenceservices.yaml b/charts/kserve-crd/templates/serving.kserve.io_inferenceservices.yaml index 644b697b62b..7fe150d3352 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_inferenceservices.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_inferenceservices.yaml @@ -936,6 +936,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1643,6 +1645,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -2399,6 +2403,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -2698,13 +2704,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -2789,6 +2792,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -2930,10 +2935,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3293,6 +3300,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3306,6 +3320,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3554,6 +3569,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3561,6 +3577,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3572,6 +3589,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3580,6 +3598,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3597,6 +3616,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -4575,6 +4595,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -5315,6 +5337,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6016,6 +6040,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6691,6 +6717,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -7404,6 +7432,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -8098,6 +8128,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -8796,6 +8828,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -9481,6 +9515,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -10173,6 +10209,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -10436,13 +10474,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -10527,6 +10562,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -10996,6 +11033,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -11683,6 +11722,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12448,6 +12489,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12723,10 +12766,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -13086,6 +13131,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -13099,6 +13151,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -13347,6 +13400,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -13354,6 +13408,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -13365,6 +13420,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -13373,6 +13429,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -13390,6 +13447,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -14352,6 +14410,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15057,6 +15117,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15770,6 +15832,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -16027,6 +16091,8 @@ spec: pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object + pipelineParallelSize: + type: integer preemptionPolicy: type: string priority: @@ -16048,13 +16114,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -16130,6 +16193,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -16163,10 +16228,10 @@ spec: type: boolean shareProcessNamespace: type: boolean - size: - type: integer subdomain: type: string + tensorParallelSize: + type: integer terminationGracePeriodSeconds: format: int64 type: integer @@ -16270,10 +16335,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -16633,6 +16700,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -16646,6 +16720,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -16894,6 +16969,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -16901,6 +16977,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -16912,6 +16989,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -16920,6 +16998,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -16937,6 +17016,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -17447,6 +17527,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -18601,6 +18683,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -19357,6 +19441,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -19656,13 +19742,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -19747,6 +19830,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -19888,10 +19973,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -20251,6 +20338,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -20264,6 +20358,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -20512,6 +20607,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -20519,6 +20615,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -20530,6 +20627,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -20538,6 +20636,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -20555,6 +20654,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/charts/kserve-crd/templates/serving.kserve.io_localmodelcaches.yaml b/charts/kserve-crd/templates/serving.kserve.io_localmodelcaches.yaml index e40ba50ac29..4606113c955 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_localmodelcaches.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_localmodelcaches.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -32,8 +31,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - nodeGroup: - type: string + nodeGroups: + items: + type: string + maxItems: 1 + minItems: 1 + type: array sourceModelUri: type: string x-kubernetes-validations: @@ -41,7 +44,7 @@ spec: rule: self == oldSelf required: - modelSize - - nodeGroup + - nodeGroups - sourceModelUri type: object status: diff --git a/charts/kserve-crd/templates/serving.kserve.io_localmodelnodegroups.yaml b/charts/kserve-crd/templates/serving.kserve.io_localmodelnodegroups.yaml index 262d2130153..0ebefe9cc0c 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_localmodelnodegroups.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_localmodelnodegroups.yaml @@ -143,10 +143,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -395,6 +397,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -546,6 +549,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -553,6 +557,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -565,6 +570,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -573,6 +579,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -591,6 +598,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/charts/kserve-crd/templates/serving.kserve.io_localmodelnodes.yaml b/charts/kserve-crd/templates/serving.kserve.io_localmodelnodes.yaml new file mode 100644 index 00000000000..f130f6e7a3b --- /dev/null +++ b/charts/kserve-crd/templates/serving.kserve.io_localmodelnodes.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.2 + name: localmodelnodes.serving.kserve.io +spec: + group: serving.kserve.io + names: + kind: LocalModelNode + listKind: LocalModelNodeList + plural: localmodelnodes + singular: localmodelnode + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + localModels: + items: + properties: + modelName: + type: string + sourceModelUri: + type: string + required: + - modelName + - sourceModelUri + type: object + type: array + required: + - localModels + type: object + status: + properties: + modelStatus: + additionalProperties: + enum: + - "" + - ModelDownloadPending + - ModelDownloading + - ModelDownloaded + - ModelDownloadError + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/kserve-crd/templates/serving.kserve.io_servingruntimes.yaml b/charts/kserve-crd/templates/serving.kserve.io_servingruntimes.yaml index eb0137bf377..f174ebc7a05 100644 --- a/charts/kserve-crd/templates/serving.kserve.io_servingruntimes.yaml +++ b/charts/kserve-crd/templates/serving.kserve.io_servingruntimes.yaml @@ -1001,6 +1001,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1335,10 +1337,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -1698,6 +1702,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -1711,6 +1722,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -1959,6 +1971,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -1966,6 +1979,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -1977,6 +1991,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -1985,6 +2000,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -2002,6 +2018,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -2963,6 +2980,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -3217,7 +3236,9 @@ spec: additionalProperties: type: string type: object - size: + pipelineParallelSize: + type: integer + tensorParallelSize: type: integer tolerations: items: @@ -3261,10 +3282,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3624,6 +3647,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3637,6 +3667,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3885,6 +3916,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3892,6 +3924,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3903,6 +3936,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3911,6 +3945,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3928,6 +3963,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/charts/kserve-resources/Chart.yaml b/charts/kserve-resources/Chart.yaml index f5e812813ae..e1bb2824c54 100644 --- a/charts/kserve-resources/Chart.yaml +++ b/charts/kserve-resources/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: kserve -version: v0.14.0 +version: v0.15.0-rc0 description: Helm chart for deploying kserve resources keywords: - kserve diff --git a/charts/kserve-resources/README.md b/charts/kserve-resources/README.md index b71aec64642..9f756aa669d 100644 --- a/charts/kserve-resources/README.md +++ b/charts/kserve-resources/README.md @@ -2,14 +2,14 @@ Helm chart for deploying kserve resources -![Version: v0.14.0](https://img.shields.io/badge/Version-v0.14.0-informational?style=flat-square) +![Version: v0.15.0-rc0](https://img.shields.io/badge/Version-v0.15.0--rc0-informational?style=flat-square) ## Installing the Chart To install the chart, run the following: ```console -$ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 +$ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.15.0-rc0 ``` ## Values @@ -17,7 +17,7 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | Key | Type | Default | Description | |-----|------|---------|-------------| | kserve.agent.image | string | `"kserve/agent"` | | -| kserve.agent.tag | string | `"v0.14.0"` | | +| kserve.agent.tag | string | `"v0.15.0-rc0"` | | | kserve.controller.affinity | object | `{}` | A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). For example: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: foo.bar.com/role operator: In values: - master | | kserve.controller.annotations | object | `{}` | Optional additional annotations to add to the controller deployment. | | kserve.controller.containerSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"privileged":false,"readOnlyRootFilesystem":true,"runAsNonRoot":true}` | Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). | @@ -27,8 +27,12 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.controller.gateway.disableIstioVirtualHost | bool | `false` | DisableIstioVirtualHost controls whether to use istio as network layer for top level component routing or path based routing. This configuration is only applicable for Serverless mode, when disabled Istio is no longer required. | | kserve.controller.gateway.domain | string | `"example.com"` | Ingress domain for RawDeployment mode, for Serverless it is configured in Knative. | | kserve.controller.gateway.domainTemplate | string | `"{{ .Name }}-{{ .Namespace }}.{{ .IngressDomain }}"` | Ingress domain template for RawDeployment mode, for Serverless mode it is configured in Knative. | -| kserve.controller.gateway.ingressGateway.className | string | `"istio"` | | -| kserve.controller.gateway.ingressGateway.gateway | string | `"knative-serving/knative-ingress-gateway"` | | +| kserve.controller.gateway.ingressGateway | object | `{"className":"istio","createGateway":false,"enableGatewayApi":false,"gateway":"knative-serving/knative-ingress-gateway","kserveGateway":"kserve/kserve-ingress-gateway"}` | ingressGateway specifies the gateway which handles the network traffic from outside the cluster. | +| kserve.controller.gateway.ingressGateway.className | string | `"istio"` | class specifies the ingress class name. If Gateway API is enabled, this will not affect the ingress routing. | +| kserve.controller.gateway.ingressGateway.createGateway | bool | `false` | createGateway controls whether to create the default Gateway resource for ingress routing as part of the installation. This is only used when Gateway API is enabled. | +| kserve.controller.gateway.ingressGateway.enableGatewayApi | bool | `false` | enableGatewayApi controls whether to use the Gateway API for ingress routing instead of kuberetes Ingress. | +| kserve.controller.gateway.ingressGateway.gateway | string | `"knative-serving/knative-ingress-gateway"` | gateway specifies the name and namespace of the Knative's ingress gateway. | +| kserve.controller.gateway.ingressGateway.kserveGateway | string | `"kserve/kserve-ingress-gateway"` | kserveGateway specifies the name and namespace of the Gateway which handles the network traffic from outside the cluster. This is only used when Gateway API is enabled. The gateway should be specified in format / | | kserve.controller.gateway.localGateway.gateway | string | `"knative-serving/knative-local-gateway"` | localGateway specifies the gateway which handles the network traffic within the cluster. | | kserve.controller.gateway.localGateway.gatewayService | string | `"knative-local-gateway.istio-system.svc.cluster.local"` | localGatewayService specifies the hostname of the local gateway service. | | kserve.controller.gateway.localGateway.knativeGatewayService | string | `""` | knativeLocalGatewayService specifies the hostname of the Knative's local gateway service. When unset, the value of "localGatewayService" will be used. When enabling strict mTLS in Istio, KServe local gateway should be created and pointed to the Knative local gateway. | @@ -55,17 +59,26 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.controller.resources | object | `{"limits":{"cpu":"100m","memory":"300Mi"},"requests":{"cpu":"100m","memory":"300Mi"}}` | Resources to provide to the kserve controller pod. For example: requests: cpu: 10m memory: 32Mi For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). | | kserve.controller.securityContext | object | `{"runAsNonRoot":true}` | Pod Security Context. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). | | kserve.controller.serviceAnnotations | object | `{}` | Optional additional annotations to add to the controller service. | -| kserve.controller.tag | string | `"v0.14.0"` | KServe controller contrainer image tag. | +| kserve.controller.tag | string | `"v0.15.0-rc0"` | KServe controller contrainer image tag. | | kserve.controller.tolerations | list | `[]` | A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). For example: tolerations: - key: foo.bar.com/role operator: Equal value: master effect: NoSchedule | | kserve.controller.topologySpreadConstraints | list | `[]` | A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core For example: topologySpreadConstraints: - maxSkew: 2 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/instance: kserve-controller-manager app.kubernetes.io/component: controller | | kserve.controller.webhookServiceAnnotations | object | `{}` | Optional additional annotations to add to the webhook service. | +| kserve.inferenceservice.resources.limits.cpu | string | `"100m"` | | +| kserve.inferenceservice.resources.limits.memory | string | `"256Mi"` | | +| kserve.inferenceservice.resources.requests.cpu | string | `"100m"` | | +| kserve.inferenceservice.resources.requests.memory | string | `"256Mi"` | | +| kserve.localmodel.agent.affinity | object | `{}` | | | kserve.localmodel.agent.hostPath | string | `"/mnt/models"` | | | kserve.localmodel.agent.image | string | `"kserve/kserve-localmodelnode-agent"` | | | kserve.localmodel.agent.nodeSelector | object | `{}` | | | kserve.localmodel.agent.reconcilationFrequencyInSecs | int | `60` | | -| kserve.localmodel.agent.tag | string | `"v0.14.0"` | | +| kserve.localmodel.agent.securityContext.runAsNonRoot | bool | `true` | | +| kserve.localmodel.agent.securityContext.runAsUser | int | `1000` | | +| kserve.localmodel.agent.tag | string | `"v0.15.0-rc0"` | | +| kserve.localmodel.agent.tolerations | list | `[]` | | | kserve.localmodel.controller.image | string | `"kserve/kserve-localmodel-controller"` | | -| kserve.localmodel.controller.tag | string | `"v0.14.0"` | | +| kserve.localmodel.controller.tag | string | `"v0.15.0-rc0"` | | +| kserve.localmodel.disableVolumeManagement | bool | `false` | | | kserve.localmodel.enabled | bool | `false` | | | kserve.localmodel.jobNamespace | string | `"kserve-localmodel-jobs"` | | | kserve.localmodel.jobTTLSecondsAfterFinished | int | `3600` | | @@ -92,10 +105,10 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.modelmesh.enabled | bool | `true` | | | kserve.modelmeshVersion | string | `"v0.12.0"` | | | kserve.router.image | string | `"kserve/router"` | | -| kserve.router.tag | string | `"v0.14.0"` | | +| kserve.router.tag | string | `"v0.15.0-rc0"` | | | kserve.security.autoMountServiceAccountToken | bool | `true` | | | kserve.service.serviceClusterIPNone | bool | `false` | | -| kserve.servingruntime.art.defaultVersion | string | `"v0.14.0"` | | +| kserve.servingruntime.art.defaultVersion | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.art.image | string | `"kserve/art-explainer"` | | | kserve.servingruntime.art.imagePullSecrets | list | `[]` | | | kserve.servingruntime.huggingfaceserver.devShm.enabled | bool | `false` | | @@ -107,14 +120,14 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.servingruntime.huggingfaceserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.huggingfaceserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.huggingfaceserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.huggingfaceserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.huggingfaceserver.tag | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.lgbserver.image | string | `"kserve/lgbserver"` | | | kserve.servingruntime.lgbserver.imagePullSecrets | list | `[]` | | | kserve.servingruntime.lgbserver.securityContext.allowPrivilegeEscalation | bool | `false` | | | kserve.servingruntime.lgbserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.lgbserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.lgbserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.lgbserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.lgbserver.tag | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.mlserver.image | string | `"docker.io/seldonio/mlserver"` | | | kserve.servingruntime.mlserver.imagePullSecrets | list | `[]` | | | kserve.servingruntime.mlserver.modelClassPlaceholder | string | `"{{.Labels.modelClass}}"` | | @@ -130,21 +143,21 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.servingruntime.paddleserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.paddleserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.paddleserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.paddleserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.paddleserver.tag | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.pmmlserver.image | string | `"kserve/pmmlserver"` | | | kserve.servingruntime.pmmlserver.imagePullSecrets | list | `[]` | | | kserve.servingruntime.pmmlserver.securityContext.allowPrivilegeEscalation | bool | `false` | | | kserve.servingruntime.pmmlserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.pmmlserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.pmmlserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.pmmlserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.pmmlserver.tag | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.sklearnserver.image | string | `"kserve/sklearnserver"` | | | kserve.servingruntime.sklearnserver.imagePullSecrets | list | `[]` | | | kserve.servingruntime.sklearnserver.securityContext.allowPrivilegeEscalation | bool | `false` | | | kserve.servingruntime.sklearnserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.sklearnserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.sklearnserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.sklearnserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.sklearnserver.tag | string | `"v0.15.0-rc0"` | | | kserve.servingruntime.tensorflow.image | string | `"tensorflow/serving"` | | | kserve.servingruntime.tensorflow.imagePullSecrets | list | `[]` | | | kserve.servingruntime.tensorflow.securityContext.allowPrivilegeEscalation | bool | `false` | | @@ -176,7 +189,7 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.servingruntime.xgbserver.securityContext.capabilities.drop[0] | string | `"ALL"` | | | kserve.servingruntime.xgbserver.securityContext.privileged | bool | `false` | | | kserve.servingruntime.xgbserver.securityContext.runAsNonRoot | bool | `true` | | -| kserve.servingruntime.xgbserver.tag | string | `"v0.14.0"` | | +| kserve.servingruntime.xgbserver.tag | string | `"v0.15.0-rc0"` | | | kserve.storage.caBundleConfigMapName | string | `""` | Mounted CA bundle config map name for storage initializer. | | kserve.storage.caBundleVolumeMountPath | string | `"/etc/ssl/custom-certs"` | Mounted path for CA bundle config map. | | kserve.storage.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | | @@ -199,5 +212,5 @@ $ helm install kserve oci://ghcr.io/kserve/charts/kserve --version v0.14.0 | kserve.storage.s3.verifySSL | string | `""` | Whether to verify the tls/ssl certificate, default to true. | | kserve.storage.storageSecretNameAnnotation | string | `"serving.kserve.io/secretName"` | Storage secret name reference for storage initializer. | | kserve.storage.storageSpecSecretName | string | `"storage-config"` | Storage spec secret name. | -| kserve.storage.tag | string | `"v0.14.0"` | | -| kserve.version | string | `"v0.14.0"` | | +| kserve.storage.tag | string | `"v0.15.0-rc0"` | | +| kserve.version | string | `"v0.15.0-rc0"` | | diff --git a/charts/kserve-resources/templates/clusterrole.yaml b/charts/kserve-resources/templates/clusterrole.yaml index 46c76a4117e..ddfb156d5cb 100644 --- a/charts/kserve-resources/templates/clusterrole.yaml +++ b/charts/kserve-resources/templates/clusterrole.yaml @@ -91,6 +91,18 @@ rules: - patch - update - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - networking.istio.io resources: diff --git a/charts/kserve-resources/templates/configmap.yaml b/charts/kserve-resources/templates/configmap.yaml index 34c7bcc6a1c..5585ecb4bfd 100644 --- a/charts/kserve-resources/templates/configmap.yaml +++ b/charts/kserve-resources/templates/configmap.yaml @@ -179,7 +179,9 @@ data: # ====================================== INGRESS CONFIGURATION ====================================== # Example ingress: |- - { + { + "enableGatewayApi": false, + "kserveIngressGateway" : "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway" : "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", @@ -192,7 +194,17 @@ data: "disableIngressCreation": false } ingress: |- - { + { + # enableGatewayApi specifies whether to use Gateway API instead of Ingress for serving external traffic. + "enableGatewayApi": false, + + # KServe implements [Gateway API](https://gateway-api.sigs.k8s.io/) to serve external traffic. + # By default, KServe configures a default gateway to serve external traffic. + # But, KServe can be configured to use a custom gateway by modifying this configuration. + # The gateway should be specified in format / + # NOTE: This configuration only applicable for raw deployment. + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + # ingressGateway specifies the ingress gateway to serve external traffic. # The gateway should be specified in format / # NOTE: This configuration only applicable for serverless deployment with Istio configured as network layer. @@ -470,6 +482,8 @@ data: # The frequency at which the local model agent reconciles the local models # This is to detect if models are missing from local disk "reconcilationFrequencyInSecs": {{ .Values.kserve.localmodel.agent.reconcilationFrequencyInSecs }} + # This is to disable localmodel pv and pvc management for namespaces without isvcs + "disableVolumeManagement": false } agent: |- @@ -533,7 +547,9 @@ data: } } ingress: |- - { + { + "enableGatewayApi": {{ .Values.kserve.controller.gateway.ingressGateway.enableGatewayApi }}, + "kserveIngressGateway" : "{{ .Values.kserve.controller.gateway.ingressGateway.kserveGateway }}", "ingressGateway" : "{{ .Values.kserve.controller.gateway.ingressGateway.gateway }}", "knativeLocalGatewayService" : "{{ .Values.kserve.controller.gateway.localGateway.knativeGatewayService }}", "localGateway" : "{{ .Values.kserve.controller.gateway.localGateway.gateway }}", @@ -585,9 +601,20 @@ data: "jobTTLSecondsAfterFinished": {{ .Values.kserve.localmodel.jobTTLSecondsAfterFinished }}, "defaultJobImage": "kserve/storage-initializer:latest", "fsGroup": {{ .Values.kserve.localmodel.securityContext.fsGroup }}, - "reconcilationFrequencyInSecs": {{ .Values.kserve.localmodel.agent.reconcilationFrequencyInSecs }} + "reconcilationFrequencyInSecs": {{ .Values.kserve.localmodel.agent.reconcilationFrequencyInSecs }}, + "disableVolumeManagement": {{ .Values.kserve.localmodel.disableVolumeManagement }} } security: |- { "autoMountServiceAccountToken": {{ .Values.kserve.security.autoMountServiceAccountToken }} } + + inferenceservice: |- + { + "resource": { + "cpuLimit": "{{ .Values.kserve.inferenceservice.resources.limits.cpu }}", + "cpuRequest": "{{ .Values.kserve.inferenceservice.resources.requests.cpu }}", + "memoryLimit": "{{ .Values.kserve.inferenceservice.resources.limits.memory }}", + "memoryRequest": "{{ .Values.kserve.inferenceservice.resources.requests.memory }}" + } + } diff --git a/charts/kserve-resources/templates/deployment.yaml b/charts/kserve-resources/templates/deployment.yaml index 350f015e25f..8acb084cffd 100644 --- a/charts/kserve-resources/templates/deployment.yaml +++ b/charts/kserve-resources/templates/deployment.yaml @@ -97,14 +97,14 @@ spec: value: kserve-webhook-server-cert livenessProbe: failureThreshold: 5 - initialDelaySeconds: 10 + initialDelaySeconds: 30 httpGet: path: /healthz port: 8081 timeoutSeconds: 5 readinessProbe: - initialDelaySeconds: 10 - failureThreshold: 10 + initialDelaySeconds: 30 + failureThreshold: 5 periodSeconds: 5 httpGet: path: /readyz diff --git a/charts/kserve-resources/templates/ingress_gateway.yaml b/charts/kserve-resources/templates/ingress_gateway.yaml new file mode 100644 index 00000000000..82fdc9135e0 --- /dev/null +++ b/charts/kserve-resources/templates/ingress_gateway.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.kserve.controller.gateway.ingressGateway.enableGatewayApi .Values.kserve.controller.gateway.ingressGateway.createGateway }} +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: kserve-ingress-gateway + namespace: {{ .Release.Namespace }} +spec: + gatewayClassName: envoy + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: All + infrastructure: + labels: + serving.kserve.io/gateway: kserve-ingress-gateway +{{- end }} diff --git a/charts/kserve-resources/templates/localmodelnode/daemonset.yaml b/charts/kserve-resources/templates/localmodelnode/daemonset.yaml index e5512a15be4..b254b8c3329 100644 --- a/charts/kserve-resources/templates/localmodelnode/daemonset.yaml +++ b/charts/kserve-resources/templates/localmodelnode/daemonset.yaml @@ -27,6 +27,14 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.kserve.localmodel.agent.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.kserve.localmodel.agent.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} serviceAccountName: kserve-localmodelnode-agent securityContext: runAsNonRoot: true @@ -43,7 +51,8 @@ spec: - ALL privileged: false readOnlyRootFilesystem: true - runAsNonRoot: true + runAsNonRoot: {{ .Values.kserve.localmodel.agent.securityContext.runAsNonRoot }} + runAsUser: {{ .Values.kserve.localmodel.agent.securityContext.runAsUser }} env: - name: POD_NAMESPACE valueFrom: diff --git a/charts/kserve-resources/templates/localmodelnode/namespace.yaml b/charts/kserve-resources/templates/localmodelnode/namespace.yaml deleted file mode 100644 index 5b60f0b8c39..00000000000 --- a/charts/kserve-resources/templates/localmodelnode/namespace.yaml +++ /dev/null @@ -1,7 +0,0 @@ -{{- if .Values.kserve.localmodel.enabled }} ---- -apiVersion: v1 -kind: Namespace -metadata: - name: {{.Values.kserve.localmodel.jobNamespace}} -{{- end }} diff --git a/charts/kserve-resources/templates/modelmesh/deployment.yaml b/charts/kserve-resources/templates/modelmesh/deployment.yaml index dc161c30caa..622efa17fd6 100644 --- a/charts/kserve-resources/templates/modelmesh/deployment.yaml +++ b/charts/kserve-resources/templates/modelmesh/deployment.yaml @@ -58,7 +58,7 @@ spec: httpGet: path: /healthz port: 8081 - initialDelaySeconds: 15 + initialDelaySeconds: 30 periodSeconds: 10 name: manager ports: @@ -69,7 +69,7 @@ spec: httpGet: path: /readyz port: 8081 - initialDelaySeconds: 10 + initialDelaySeconds: 30 periodSeconds: 5 resources: limits: diff --git a/charts/kserve-resources/values.yaml b/charts/kserve-resources/values.yaml index dfe52b9a548..75e5fa6c628 100644 --- a/charts/kserve-resources/values.yaml +++ b/charts/kserve-resources/values.yaml @@ -1,5 +1,5 @@ kserve: - version: &defaultVersion v0.14.0 + version: &defaultVersion v0.15.0-rc0 modelmeshVersion: &defaultModelMeshVersion v0.12.0 agent: image: kserve/agent @@ -175,8 +175,18 @@ kserve: # -- knativeLocalGatewayService specifies the hostname of the Knative's local gateway service. # When unset, the value of "localGatewayService" will be used. When enabling strict mTLS in Istio, KServe local gateway should be created and pointed to the Knative local gateway. knativeGatewayService: "" + # -- ingressGateway specifies the gateway which handles the network traffic from outside the cluster. ingressGateway: + # -- enableGatewayApi controls whether to use the Gateway API for ingress routing instead of kuberetes Ingress. + enableGatewayApi: false + # -- kserveGateway specifies the name and namespace of the Gateway which handles the network traffic from outside the cluster. + # This is only used when Gateway API is enabled. The gateway should be specified in format / + kserveGateway: kserve/kserve-ingress-gateway + # -- createGateway controls whether to create the default Gateway resource for ingress routing as part of the installation. This is only used when Gateway API is enabled. + createGateway: false + # -- gateway specifies the name and namespace of the Knative's ingress gateway. gateway: knative-serving/knative-ingress-gateway + # -- class specifies the ingress class name. If Gateway API is enabled, this will not affect the ingress routing. className: istio # -- The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. @@ -418,11 +428,25 @@ kserve: jobTTLSecondsAfterFinished: 3600 securityContext: fsGroup: 1000 + disableVolumeManagement: false agent: nodeSelector: {} + affinity: {} + tolerations: [] hostPath: /mnt/models image: kserve/kserve-localmodelnode-agent tag: *defaultVersion reconcilationFrequencyInSecs: 60 + securityContext: + runAsUser: 1000 + runAsNonRoot: true security: autoMountServiceAccountToken: true + inferenceservice: + resources: + limits: + cpu: 100m + memory: 256Mi + requests: + cpu: 100m + memory: 256Mi diff --git a/cmd/manager/main.go b/cmd/manager/main.go index d9a6668e0f7..103932e87e6 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -41,6 +41,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager/signals" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" "github.com/kserve/kserve/pkg/apis/serving/v1beta1" @@ -189,6 +190,13 @@ func main() { } } } + + setupLog.Info("Setting up gateway api scheme") + if err := gatewayapiv1.Install(mgr.GetScheme()); err != nil { + setupLog.Error(err, "unable to add Gateway APIs to scheme") + os.Exit(1) + } + if err = routev1.AddToScheme(mgr.GetScheme()); err != nil { setupLog.Error(err, "unable to add routev1 APIs to scheme") os.Exit(1) diff --git a/cmd/router/main.go b/cmd/router/main.go index 01f5e7a4604..92b56984b59 100644 --- a/cmd/router/main.go +++ b/cmd/router/main.go @@ -18,29 +18,30 @@ package main import ( "bytes" + "context" + "crypto/rand" "encoding/json" goerrors "errors" "fmt" "io" + "math/big" "net/http" "os" + "os/signal" "regexp" "strconv" "strings" + "syscall" "time" - "github.com/kserve/kserve/pkg/constants" "github.com/pkg/errors" - + flag "github.com/spf13/pflag" "github.com/tidwall/gjson" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "crypto/rand" - "math/big" - "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - flag "github.com/spf13/pflag" + "github.com/kserve/kserve/pkg/constants" ) var log = logf.Log.WithName("InferenceGraphRouter") @@ -335,9 +336,21 @@ func compilePatterns(patterns []string) ([]*regexp.Regexp, error) { return compiled, goerrors.Join(allErrors...) } +// Mainly used for kubernetes readiness probe. It responds with "503 shutting down" if server is shutting down, +// otherwise returns "200 OK". +func readyHandler(w http.ResponseWriter, req *http.Request) { + if isShuttingDown { + http.Error(w, "shutting down", http.StatusServiceUnavailable) + } else { + w.WriteHeader(http.StatusOK) + } +} + var ( jsonGraph = flag.String("graph-json", "", "serialized json graph def") compiledHeaderPatterns []*regexp.Regexp + isShuttingDown = false + drainSleepDuration = 30 * time.Second ) func main() { @@ -360,18 +373,44 @@ func main() { } http.HandleFunc("/", graphHandler) + http.HandleFunc(constants.RouterReadinessEndpoint, readyHandler) server := &http.Server{ - Addr: ":8080", // specify the address and port - Handler: http.HandlerFunc(graphHandler), // specify your HTTP handler - ReadTimeout: time.Minute, // set the maximum duration for reading the entire request, including the body - WriteTimeout: time.Minute, // set the maximum duration before timing out writes of the response - IdleTimeout: 3 * time.Minute, // set the maximum amount of time to wait for the next request when keep-alives are enabled + Addr: ":" + strconv.Itoa(constants.RouterPort), + Handler: nil, // default server mux + ReadTimeout: time.Minute, // https://medium.com/a-journey-with-go/go-understand-and-mitigate-slowloris-attack-711c1b1403f6 + WriteTimeout: time.Minute, // set the maximum duration before timing out writes of the response + IdleTimeout: 3 * time.Minute, // set the maximum amount of time to wait for the next request when keep-alives are enabled } - err = server.ListenAndServe() - if err != nil { - log.Error(err, "failed to listen on 8080") + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Error(err, fmt.Sprintf("Failed to serve on address %v", server.Addr)) + os.Exit(1) + } + }() + + // Blocks until SIGTERM or SIGINT is received + handleSignals(server) +} + +func handleSignals(server *http.Server) { + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) + + sig := <-signalChan + log.Info("Received shutdown signal", "signal", sig) + // Fail the readiness probe + isShuttingDown = true + log.Info("Sleeping %v to allow K8s propagation of non-ready state", drainSleepDuration) + // Sleep to give networking a little bit more time to remove the pod + // from its configuration and propagate that to all loadbalancers and nodes. + time.Sleep(drainSleepDuration) + // Shut down the server gracefully + if err := server.Shutdown(context.Background()); err != nil { + log.Error(err, "Failed to shutdown the server gracefully") os.Exit(1) } + log.Info("Server gracefully shutdown") } diff --git a/config/configmap/inferenceservice.yaml b/config/configmap/inferenceservice.yaml index 3c8ac538acd..4b6aab730ba 100644 --- a/config/configmap/inferenceservice.yaml +++ b/config/configmap/inferenceservice.yaml @@ -41,7 +41,38 @@ data: "defaultImageVersion": "latest" } } - + # ====================================== ISVC CONFIGURATION ====================================== + # Example + inferenceService: |- + { + "serviceAnnotationDisallowedList": [ + "my.custom.annotation/1" + ], + "serviceLabelDisallowedList": [ + "my.custom.label.1" + ] + } + # Example of isvc configuration + inferenceService: |- + { + # ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative + # revisions, which prevents the reconciliation loop to be triggered if the annotations is + # configured here are used. + # Default values are: + # "autoscaling.knative.dev/min-scale", + # "autoscaling.knative.dev/max-scale", + # "internal.serving.kserve.io/storage-initializer-sourceuri", + # "kubectl.kubernetes.io/last-applied-configuration" + # Any new value will be appended to the list. + "serviceAnnotationDisallowedList": [ + "my.custom.annotation/1" + ], + # ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions + # which prevents the reconciliation loop to be triggered if the labels is configured here are used. + "serviceLabelDisallowedList": [ + "my.custom.label.1" + ] + } # ====================================== STORAGE INITIALIZER CONFIGURATION ====================================== # Example storageInitializer: |- @@ -190,7 +221,9 @@ data: # ====================================== INGRESS CONFIGURATION ====================================== # Example ingress: |- - { + { + "enableGatewayApi": false, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway" : "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", @@ -203,7 +236,17 @@ data: "disableIngressCreation": false } ingress: |- - { + { + # enableGatewayApi specifies whether to use Gateway API instead of Ingress to serve external traffic. + "enableGatewayApi": false, + + # KServe implements [Gateway API](https://gateway-api.sigs.k8s.io/) to serve external traffic. + # By default, KServe configures a default gateway to serve external traffic. + # But, KServe can be configured to use a custom gateway by modifying this configuration. + # The gateway should be specified in format / + # NOTE: This configuration only applicable for raw deployment. + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + # ingressGateway specifies the ingress gateway to serve external traffic. # The gateway should be specified in format / # NOTE: This configuration only applicable for serverless deployment with Istio configured as network layer. @@ -480,8 +523,42 @@ data: "jobTTLSecondsAfterFinished": 3600, # The frequency at which the local model agent reconciles the local models # This is to detect if models are missing from local disk - "reconcilationFrequencyInSecs": 60 + "reconcilationFrequencyInSecs": 60, + # This is to disable localmodel pv and pvc management for namespaces without isvcs + "disableVolumeManagement": false } + + # ====================================== LOCALMODEL CONFIGURATION ====================================== + # Example + inferenceservice: |- + { + "resource": { + "cpuLimit": "1", + "memoryLimit": "2Gi", + "cpuRequest": "1", + "memoryRequest": "2Gi" + } + } + inferenceservice: |- + { + # resource contains the default resource configuration for the inference service. + # you can override this configuration by specifying the resources in the inference service yaml. + # If you want to unbound the resource (limits and requests), you can set the value to null or "" + # or just remove the specific field from the config. + "resource": { + # cpuLimit is the limits.cpu to set for the inference service. + "cpuLimit": "1", + + # memoryLimit is the limits.memory to set for the inference service. + "memoryLimit": "2Gi", + + # cpuRequest is the requests.cpu to set for the inference service. + "cpuRequest": "1", + + # memoryRequest is the requests.memory to set for the inference service. + "memoryRequest": "2Gi" + } + } explainers: |- { @@ -528,7 +605,9 @@ data: } ingress: |- - { + { + "enableGatewayApi": false, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway" : "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", @@ -602,6 +681,16 @@ data: { "autoMountServiceAccountToken": true } + + inferenceservice: |- + { + "resource": { + "cpuLimit": "1", + "memoryLimit": "2Gi", + "cpuRequest": "1", + "memoryRequest": "2Gi" + } + } service: |- { diff --git a/config/crd/full/serving.kserve.io_clusterservingruntimes.yaml b/config/crd/full/serving.kserve.io_clusterservingruntimes.yaml index ae9e15eed33..556950f31ba 100644 --- a/config/crd/full/serving.kserve.io_clusterservingruntimes.yaml +++ b/config/crd/full/serving.kserve.io_clusterservingruntimes.yaml @@ -1002,6 +1002,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1336,10 +1338,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -1699,6 +1703,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -1712,6 +1723,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -1960,6 +1972,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -1967,6 +1980,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -1978,6 +1992,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -1986,6 +2001,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -2003,6 +2019,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -2964,6 +2981,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -3264,10 +3283,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3627,6 +3648,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3640,6 +3668,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3888,6 +3917,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3895,6 +3925,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3906,6 +3937,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3914,6 +3946,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3931,6 +3964,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/config/crd/full/serving.kserve.io_clusterstoragecontainers.yaml b/config/crd/full/serving.kserve.io_clusterstoragecontainers.yaml index 2a55ab532fe..e48c2660370 100644 --- a/config/crd/full/serving.kserve.io_clusterstoragecontainers.yaml +++ b/config/crd/full/serving.kserve.io_clusterstoragecontainers.yaml @@ -470,6 +470,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object diff --git a/config/crd/full/serving.kserve.io_inferencegraphs.yaml b/config/crd/full/serving.kserve.io_inferencegraphs.yaml index c1a577f549b..2b8c629cea3 100644 --- a/config/crd/full/serving.kserve.io_inferencegraphs.yaml +++ b/config/crd/full/serving.kserve.io_inferencegraphs.yaml @@ -527,6 +527,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object diff --git a/config/crd/full/serving.kserve.io_inferenceservices.yaml b/config/crd/full/serving.kserve.io_inferenceservices.yaml index 91fca492cca..ea463cb3d98 100644 --- a/config/crd/full/serving.kserve.io_inferenceservices.yaml +++ b/config/crd/full/serving.kserve.io_inferenceservices.yaml @@ -936,6 +936,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1643,6 +1645,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -2399,6 +2403,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -2698,13 +2704,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -2789,6 +2792,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -2930,10 +2935,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3293,6 +3300,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3306,6 +3320,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3554,6 +3569,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3561,6 +3577,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3572,6 +3589,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3580,6 +3598,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3597,6 +3616,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -4575,6 +4595,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -5315,6 +5337,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6016,6 +6040,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6691,6 +6717,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -7404,6 +7432,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -8098,6 +8128,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -8796,6 +8828,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -9481,6 +9515,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -10173,6 +10209,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -10436,13 +10474,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -10527,6 +10562,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -10996,6 +11033,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -11683,6 +11722,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12448,6 +12489,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12723,10 +12766,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -13086,6 +13131,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -13099,6 +13151,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -13347,6 +13400,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -13354,6 +13408,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -13365,6 +13420,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -13373,6 +13429,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -13390,6 +13447,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -14352,6 +14410,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15057,6 +15117,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15770,6 +15832,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -16050,13 +16114,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -16132,6 +16193,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -16272,10 +16335,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -16635,6 +16700,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -16648,6 +16720,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -16896,6 +16969,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -16903,6 +16977,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -16914,6 +16989,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -16922,6 +16998,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -16939,6 +17016,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -17449,6 +17527,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -18603,6 +18683,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -19359,6 +19441,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -19658,13 +19742,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -19749,6 +19830,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -19890,10 +19973,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -20253,6 +20338,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -20266,6 +20358,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -20514,6 +20607,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -20521,6 +20615,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -20532,6 +20627,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -20540,6 +20636,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -20557,6 +20654,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/config/crd/full/serving.kserve.io_localmodelnodegroups.yaml b/config/crd/full/serving.kserve.io_localmodelnodegroups.yaml index f7b995c34b1..51beae879b9 100644 --- a/config/crd/full/serving.kserve.io_localmodelnodegroups.yaml +++ b/config/crd/full/serving.kserve.io_localmodelnodegroups.yaml @@ -144,10 +144,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -396,6 +398,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -547,6 +550,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -554,6 +558,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -566,6 +571,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -574,6 +580,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -592,6 +599,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/config/crd/full/serving.kserve.io_servingruntimes.yaml b/config/crd/full/serving.kserve.io_servingruntimes.yaml index c63bee0926d..b5f5e6bc55b 100644 --- a/config/crd/full/serving.kserve.io_servingruntimes.yaml +++ b/config/crd/full/serving.kserve.io_servingruntimes.yaml @@ -1002,6 +1002,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1336,10 +1338,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -1699,6 +1703,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -1712,6 +1723,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -1960,6 +1972,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -1967,6 +1980,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -1978,6 +1992,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -1986,6 +2001,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -2003,6 +2019,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -2964,6 +2981,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -3264,10 +3283,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3627,6 +3648,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3640,6 +3668,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3888,6 +3917,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3895,6 +3925,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3906,6 +3937,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3914,6 +3946,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3931,6 +3964,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 32a54719e53..76f28871152 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -79,6 +79,7 @@ replacements: kind: Certificate name: serving-cert namespace: kserve +# Replace the namespace with the namespace of the controller manager. - source: fieldPath: metadata.namespace kind: Deployment diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index c75dbddb54b..9702c14495c 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -47,14 +47,14 @@ spec: value: kserve-webhook-server-cert livenessProbe: failureThreshold: 5 - initialDelaySeconds: 10 + initialDelaySeconds: 30 httpGet: path: /healthz port: 8081 timeoutSeconds: 5 readinessProbe: - initialDelaySeconds: 10 - failureThreshold: 10 + initialDelaySeconds: 30 + failureThreshold: 5 periodSeconds: 5 httpGet: path: /readyz diff --git a/config/overlays/kubeflow/kustomization.yaml b/config/overlays/kubeflow/kustomization.yaml index 5a2ff6fea5a..8268d0d6aba 100644 --- a/config/overlays/kubeflow/kustomization.yaml +++ b/config/overlays/kubeflow/kustomization.yaml @@ -21,6 +21,7 @@ configurations: - params.yaml replacements: +# Replace the namespace with the namespace of the controller manager. - source: fieldPath: metadata.namespace kind: Deployment @@ -126,7 +127,6 @@ replacements: options: delimiter: '/' index: 0 - patches: - path: patches/statefulset.yaml - path: patches/namespace.yaml diff --git a/config/overlays/test/configmap/inferenceservice-disable-istio.yaml b/config/overlays/test/configmap/inferenceservice-disable-istio.yaml index c96d934e11f..946582fb99b 100644 --- a/config/overlays/test/configmap/inferenceservice-disable-istio.yaml +++ b/config/overlays/test/configmap/inferenceservice-disable-istio.yaml @@ -5,7 +5,8 @@ metadata: namespace: kserve data: ingress: |- - { + { + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway" : "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", diff --git a/config/overlays/test/configmap/inferenceservice-enable-gateway-api.yaml b/config/overlays/test/configmap/inferenceservice-enable-gateway-api.yaml new file mode 100644 index 00000000000..47f90e7646c --- /dev/null +++ b/config/overlays/test/configmap/inferenceservice-enable-gateway-api.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: inferenceservice-config + namespace: kserve +data: + ingress: |- + { + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway" : "knative-serving/knative-ingress-gateway", + "localGateway" : "knative-serving/knative-local-gateway", + "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", + "ingressDomain" : "example.com", + "ingressClassName" : "istio", + "domainTemplate": "{{ .Name }}-{{ .Namespace }}.{{ .IngressDomain }}", + "urlScheme": "http", + "disableIstioVirtualHost": false + } diff --git a/config/overlays/test/configmap/inferenceservice-enable-modelcache.yaml b/config/overlays/test/configmap/inferenceservice-enable-modelcache.yaml new file mode 100644 index 00000000000..92b02f30821 --- /dev/null +++ b/config/overlays/test/configmap/inferenceservice-enable-modelcache.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: inferenceservice-config + namespace: kserve +data: + localModel: |- + { + "enabled": true, + "jobNamespace": "kserve-localmodel-jobs", + "defaultJobImage" : "kserve/storage-initializer:latest", + "fsGroup": 1000 + } \ No newline at end of file diff --git a/config/overlays/test/configmap/inferenceservice-ingress.yaml b/config/overlays/test/configmap/inferenceservice-path-template.yaml similarity index 84% rename from config/overlays/test/configmap/inferenceservice-ingress.yaml rename to config/overlays/test/configmap/inferenceservice-path-template.yaml index 323784eb21a..0630249a17b 100644 --- a/config/overlays/test/configmap/inferenceservice-ingress.yaml +++ b/config/overlays/test/configmap/inferenceservice-path-template.yaml @@ -5,7 +5,9 @@ metadata: namespace: kserve data: ingress: |- - { + { + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway": "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", diff --git a/config/overlays/test/configmap/inferenceservice.yaml b/config/overlays/test/configmap/inferenceservice.yaml index f1aafac4333..784cf5e35f7 100644 --- a/config/overlays/test/configmap/inferenceservice.yaml +++ b/config/overlays/test/configmap/inferenceservice.yaml @@ -17,7 +17,8 @@ data: "memoryRequest": "100Mi", "memoryLimit": "1Gi", "cpuRequest": "100m", - "cpuLimit": "1" + "cpuLimit": "1", + "enableDirectPvcVolumeMount": true } credentials: |- { @@ -31,6 +32,8 @@ data: } ingress: |- { + "enableGatewayApi": false, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway" : "knative-serving/knative-ingress-gateway", "localGateway": "knative-serving/knative-local-gateway", "localGatewayService" : "knative-local-gateway.istio-system.svc.cluster.local", diff --git a/config/overlays/test/gateway/ingress_gateway.yaml b/config/overlays/test/gateway/ingress_gateway.yaml new file mode 100644 index 00000000000..f7f315f8c62 --- /dev/null +++ b/config/overlays/test/gateway/ingress_gateway.yaml @@ -0,0 +1,17 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: kserve-ingress-gateway + namespace: kserve +spec: + gatewayClassName: envoy + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: All + infrastructure: + labels: + serving.kserve.io/gateway: kserve-ingress-gateway diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index ae522f6940f..88c9064f1d1 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -78,6 +78,18 @@ rules: - patch - update - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - networking.istio.io resources: diff --git a/config/runtimes/kserve-huggingfaceserver-multinode.yaml b/config/runtimes/kserve-huggingfaceserver-multinode.yaml index 1c134f00739..f6c93004076 100644 --- a/config/runtimes/kserve-huggingfaceserver-multinode.yaml +++ b/config/runtimes/kserve-huggingfaceserver-multinode.yaml @@ -16,35 +16,33 @@ spec: - v1 containers: - name: kserve-container - image: kserve/huggingfaceserver:latest + image: kserve/huggingfaceserver:latest-gpu command: ["bash", "-c"] args: - | - ray start --head --disable-usage-stats --include-dashboard false - # wait for other node to join - until [[ $(ray status | grep -c node_) -eq ${PIPELINE_PARALLEL_SIZE} ]]; do - echo "Waiting..." - sleep 1 - done - ray status - export MODEL=${MODEL_ID} if [[ ! -z ${MODEL_DIR} ]] then - MODEL=${MODEL_DIR} + export MODEL=${MODEL_DIR} fi - python3 -m huggingfaceserver --model_name=${MODEL_NAME} --model_dir=${MODEL} --tensor-parallel-size=${TENSOR_PARALLEL_SIZE} --pipeline-parallel-size=${PIPELINE_PARALLEL_SIZE} + export RAY_ADDRESS=${POD_IP}:${RAY_PORT} + ray start --head --disable-usage-stats --include-dashboard false + python ./huggingfaceserver/health_check.py registered_nodes --retries 200 --probe_name runtime_start + + python -m huggingfaceserver --model_name=${MODEL_NAME} --model_dir=${MODEL} --tensor-parallel-size=${TENSOR_PARALLEL_SIZE} --pipeline-parallel-size=${PIPELINE_PARALLEL_SIZE} env: - name: RAY_PORT - value: "6379" - - name: RAY_ADDRESS - value: 127.0.0.1:6379 + value: "6379" - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP - name: VLLM_CONFIG_ROOT value: /tmp - name: HF_HUB_CACHE @@ -60,41 +58,39 @@ spec: - name: shm mountPath: /dev/shm livenessProbe: - failureThreshold: 3 - periodSeconds: 30 + failureThreshold: 2 + periodSeconds: 5 successThreshold: 1 - timeoutSeconds: 5 - initialDelaySeconds: 10 + timeoutSeconds: 15 exec: command: - bash - -c - | - ./huggingfaceserver/health_check.py liveness + python ./huggingfaceserver/health_check.py registered_node_and_runtime_health --health_check_url http://localhost:8080 --probe_name head_liveness readinessProbe: failureThreshold: 2 - periodSeconds: 10 + periodSeconds: 5 successThreshold: 1 - timeoutSeconds: 5 - initialDelaySeconds: 10 + timeoutSeconds: 15 exec: command: - bash - -c - | - ./huggingfaceserver/health_check.py readiness ${PIPELINE_PARALLEL_SIZE} http://localhost:8080 + python ./huggingfaceserver/health_check.py runtime_health --health_check_url http://localhost:8080 --probe_name head_readiness startupProbe: failureThreshold: 40 periodSeconds: 30 successThreshold: 1 - timeoutSeconds: 5 - initialDelaySeconds: 5 + timeoutSeconds: 30 + initialDelaySeconds: 60 exec: command: - bash - -c - | - ./huggingfaceserver/health_check.py startup + python ./huggingfaceserver/health_check.py registered_node_and_runtime_health --health_check_url http://localhost:8080 --probe_name head_startup volumes: - name: shm emptyDir: @@ -105,33 +101,34 @@ spec: tensorParallelSize: 1 containers: - name: worker-container - image: kserve/huggingfaceserver:latest + image: kserve/huggingfaceserver:latest-gpu command: ["bash", "-c"] args: - | + export RAY_HEAD_ADDRESS=${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local:6379 SECONDS=0 while true; do - if (( SECONDS <= 120 )); then - if ray health-check --address "${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local:6379" > /dev/null 2>&1; then - echo "Global Control Service(GCS) is ready." + if (( SECONDS <= 240 )); then + if ray health-check --address "${RAY_HEAD_ADDRESS}" > /dev/null 2>&1; then + echo "Ray Global Control Service(GCS) is ready." break fi - echo "$SECONDS seconds elapsed: Waiting for Global Control Service(GCS) to be ready." + echo "$SECONDS seconds elapsed: Waiting for Ray Global Control Service(GCS) to be ready." else - if ray health-check --address "${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local:6379"; then - echo "Global Control Service(GCS) is ready. Any error messages above can be safely ignored." + if ray health-check --address "${RAY_HEAD_ADDRESS}"; then + echo "Ray Global Control Service(GCS) is ready. Any error messages above can be safely ignored." break fi - echo "$SECONDS seconds elapsed: Still waiting for Global Control Service(GCS) to be ready." + echo "$SECONDS seconds elapsed: Still waiting for Ray Global Control Service(GCS) to be ready." fi - + sleep 5 done - RAY_HEAD_ADDRESS="${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local:6379" echo "Attempting to connect to Ray cluster at $RAY_HEAD_ADDRESS ..." - ray start --address="$RAY_HEAD_ADDRESS" --block + ray start --address="${RAY_HEAD_ADDRESS}" --block + env: - name: POD_NAME valueFrom: @@ -141,6 +138,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + resources: requests: cpu: "2" @@ -152,27 +150,31 @@ spec: - name: shm mountPath: /dev/shm livenessProbe: - failureThreshold: 3 + failureThreshold: 2 periodSeconds: 5 successThreshold: 1 - timeoutSeconds: 5 + timeoutSeconds: 15 exec: command: - bash - -c - | - ./huggingfaceserver/health_check.py registered_nodes ${PIPELINE_PARALLEL_SIZE} + export RAY_ADDRESS=${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local:6379 + python ./huggingfaceserver/health_check.py registered_nodes --probe_name worker_liveness startupProbe: - failureThreshold: 12 - periodSeconds: 5 + failureThreshold: 40 + periodSeconds: 30 successThreshold: 1 - timeoutSeconds: 5 + timeoutSeconds: 30 + initialDelaySeconds: 60 exec: command: - bash - - -c + - -c - | - ./huggingfaceserver/health_check.py startup + export RAY_HEAD_NODE=${HEAD_SVC}.${POD_NAMESPACE}.svc.cluster.local + export RAY_ADDRESS=${RAY_HEAD_NODE}:6379 + python ./huggingfaceserver/health_check.py registered_node_and_runtime_models --runtime_url http://${RAY_HEAD_NODE}:8080/v1/models --probe_name worker_startup volumes: - name: shm emptyDir: diff --git a/docs/samples/explanation/alibi/alibiexplainer/poetry.lock b/docs/samples/explanation/alibi/alibiexplainer/poetry.lock index c5b71d55ae9..fe7e8592aa0 100644 --- a/docs/samples/explanation/alibi/alibiexplainer/poetry.lock +++ b/docs/samples/explanation/alibi/alibiexplainer/poetry.lock @@ -1865,7 +1865,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/docs/samples/explanation/alibi/alibiexplainer/pyproject.toml b/docs/samples/explanation/alibi/alibiexplainer/pyproject.toml index 0430b71c3b5..aa31bc29409 100644 --- a/docs/samples/explanation/alibi/alibiexplainer/pyproject.toml +++ b/docs/samples/explanation/alibi/alibiexplainer/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "alibiexplainer" -version = "0.14.0rc1" +version = "0.15.0rc0" description = "Model Explanation Server. Not intended for use outside KServe Frameworks Images." authors = ["cliveseldon "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/go.mod b/go.mod index 70429550116..69e3f0c2649 100644 --- a/go.mod +++ b/go.mod @@ -31,10 +31,10 @@ require ( gopkg.in/go-playground/validator.v9 v9.31.0 istio.io/api v1.23.0 istio.io/client-go v1.23.0 - k8s.io/api v0.31.2 - k8s.io/apimachinery v0.31.2 - k8s.io/client-go v0.31.0 - k8s.io/code-generator v0.31.0 + k8s.io/api v0.31.1 + k8s.io/apimachinery v0.31.1 + k8s.io/client-go v0.31.1 + k8s.io/code-generator v0.31.1 k8s.io/component-helpers v0.30.4 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 @@ -42,7 +42,8 @@ require ( knative.dev/networking v0.0.0-20240815142417-37fdbdd0854b knative.dev/pkg v0.0.0-20240815051656-89743d9bbf7c knative.dev/serving v0.42.2 - sigs.k8s.io/controller-runtime v0.19.1 + sigs.k8s.io/controller-runtime v0.19.2 + sigs.k8s.io/gateway-api v1.2.1 sigs.k8s.io/yaml v1.4.0 ) @@ -118,28 +119,31 @@ require ( go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/genproto v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect - google.golang.org/grpc v1.66.0 // indirect + google.golang.org/grpc v1.66.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/apiextensions-apiserver v0.31.1 // indirect k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) + +// Fixes CVE-2024-45338 +replace golang.org/x/net => golang.org/x/net v0.33.0 diff --git a/go.sum b/go.sum index aa896776745..4882bfe6e6f 100644 --- a/go.sum +++ b/go.sum @@ -395,6 +395,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -427,13 +428,12 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -466,44 +466,14 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -524,8 +494,12 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -548,7 +522,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -557,31 +530,31 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -629,6 +602,9 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -712,8 +688,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -768,16 +744,16 @@ istio.io/api v1.23.0 h1:yqv3lNW6XSYS5XkbEkxsmFROXIQznp4lFWqj7xKEqCA= istio.io/api v1.23.0/go.mod h1:QPSTGXuIQdnZFEm3myf9NZ5uBMwCdJWUvfj9ZZ+2oBM= istio.io/client-go v1.23.0 h1://xojbifr84q29WE3eMx74p36hD4lvcejX1KxE3iJvY= istio.io/client-go v1.23.0/go.mod h1:3qX/KBS5aR47QV4JhphcZl5ysnZ53x78TBjNQLM2TC4= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= -k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= -k8s.io/code-generator v0.31.0 h1:w607nrMi1KeDKB3/F/J4lIoOgAwc+gV9ZKew4XRfMp8= -k8s.io/code-generator v0.31.0/go.mod h1:84y4w3es8rOJOUUP1rLsIiGlO1JuEaPFXQPA9e/K6U0= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= +k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/code-generator v0.31.1 h1:GvkRZEP2g2UnB2QKT2Dgc/kYxIkDxCHENv2Q1itioVs= +k8s.io/code-generator v0.31.1/go.mod h1:oL2ky46L48osNqqZAeOcWWy0S5BXj50vVdwOtTefqIs= k8s.io/component-helpers v0.30.4 h1:A4KYmrz12HZtGZ8TAnanl0SUx7n6tKduxzB3NHvinr0= k8s.io/component-helpers v0.30.4/go.mod h1:h5D4gI8hGQXMHw90qJq41PRUJrn2dvFA3ElZFUTzRps= k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7 h1:cErOOTkQ3JW19o4lo91fFurouhP8NcoBvb7CkvhZZpk= @@ -797,8 +773,10 @@ knative.dev/serving v0.42.2/go.mod h1:3cgU8/864RcqA0ZPrc3jFcmS3uJL/mOlUZiYsXonwa rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= -sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.2 h1:3sPrF58XQEPzbE8T81TN6selQIMGbtYwuaJ6eDssDF8= +sigs.k8s.io/controller-runtime v0.19.2/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/gateway-api v1.2.1 h1:fZZ/+RyRb+Y5tGkwxFKuYuSRQHu9dZtbjenblleOLHM= +sigs.k8s.io/gateway-api v1.2.1/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/hack/generate-install.sh b/hack/generate-install.sh index 9e691ca2717..0f461ad5147 100755 --- a/hack/generate-install.sh +++ b/hack/generate-install.sh @@ -59,6 +59,7 @@ RELEASES=( "v0.14.0-rc0" "v0.14.0-rc1" "v0.14.0" + "v0.15.0-rc0" ) TAG=$1 diff --git a/hack/quick_install.sh b/hack/quick_install.sh index 71f78c87df7..0a7bd692a8f 100755 --- a/hack/quick_install.sh +++ b/hack/quick_install.sh @@ -20,8 +20,9 @@ Help() { export ISTIO_VERSION=1.23.2 export KNATIVE_OPERATOR_VERSION=v1.15.7 export KNATIVE_SERVING_VERSION=1.15.2 -export KSERVE_VERSION=v0.14.0 +export KSERVE_VERSION=v0.15.0-rc0 export CERT_MANAGER_VERSION=v1.16.1 +export GATEWAY_API_VERSION=v1.2.1 SCRIPT_DIR="$(dirname -- "${BASH_SOURCE[0]}")" export SCRIPT_DIR @@ -86,6 +87,9 @@ if [ "$(get_kube_version)" -lt 24 ]; then exit 1 fi +echo "Installing Gateway API CRDs ..." +kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/${GATEWAY_API_VERSION}/standard-install.yaml + helm repo add istio https://istio-release.storage.googleapis.com/charts --force-update helm install istio-base istio/base -n istio-system --wait --set defaultRevision=default --create-namespace --version ${ISTIO_VERSION} helm install istiod istio/istiod -n istio-system --wait --version ${ISTIO_VERSION} \ diff --git a/hack/verify-golint.sh b/hack/verify-golint.sh index 217919db726..cb78c80ef95 100755 --- a/hack/verify-golint.sh +++ b/hack/verify-golint.sh @@ -18,7 +18,11 @@ set -o errexit set -o pipefail # golangci-lint binary path +# Check if GOBIN is set, if not use GOPATH/bin golangci_lint_binary="$(go env GOPATH)/bin/golangci-lint" +if [ -n "$(go env GOBIN)" ]; then + golangci_lint_binary="$(go env GOBIN)/golangci-lint" +fi # Check if golangci-lint is already installed if ! command -v golangci-lint &> /dev/null; then diff --git a/hack/violation_exceptions.list b/hack/violation_exceptions.list index 2e4589521d4..59bcd530252 100644 --- a/hack/violation_exceptions.list +++ b/hack/violation_exceptions.list @@ -13,6 +13,8 @@ API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/ API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1alpha1,TrainedModelList,Items API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ComponentStatusSpec,Traffic API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,InferenceServiceList,Items +API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,InferenceServicesConfig,ServiceAnnotationDisallowedList +API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,InferenceServicesConfig,ServiceLabelDisallowedList API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,LoggerSpec,MetadataHeaders API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,PodSpec,Containers API rule violation: list_type_missing,github.com/kserve/kserve/pkg/apis/serving/v1beta1,PodSpec,EphemeralContainers @@ -33,6 +35,7 @@ API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ExplainerConfig,ContainerImage API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ExplainerExtensionSpec,StorageURI API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ExplainersConfig,ARTExplainer +API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,IngressConfig,EnableGatewayAPI API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,IngressConfig,LocalGatewayServiceName API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ModelStatus,ModelCopies API rule violation: names_match,github.com/kserve/kserve/pkg/apis/serving/v1beta1,ModelStatus,ModelRevisionStates diff --git a/localmodelnode.Dockerfile b/localmodel-agent.Dockerfile similarity index 100% rename from localmodelnode.Dockerfile rename to localmodel-agent.Dockerfile diff --git a/pkg/agent/storage/https.go b/pkg/agent/storage/https.go index 694137255ed..cac1f583e8b 100644 --- a/pkg/agent/storage/https.go +++ b/pkg/agent/storage/https.go @@ -142,6 +142,7 @@ func (h *HTTPSDownloader) extractHeaders() (headers map[string]string, err error } func createNewFile(fileFullName string) (*os.File, error) { + fileFullName = filepath.Clean(fileFullName) if FileExists(fileFullName) { if err := os.Remove(fileFullName); err != nil { return nil, fmt.Errorf("file is unable to be deleted: %w", err) diff --git a/pkg/apis/serving/v1beta1/component.go b/pkg/apis/serving/v1beta1/component.go index f00a33d7129..39a43d5a7b2 100644 --- a/pkg/apis/serving/v1beta1/component.go +++ b/pkg/apis/serving/v1beta1/component.go @@ -117,7 +117,6 @@ type ComponentExtensionSpec struct { // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ // +optional Annotations map[string]string `json:"annotations,omitempty"` - // The deployment strategy to use to replace existing pods with new ones. Only applicable for raw deployment mode. // +optional DeploymentStrategy *appsv1.DeploymentStrategy `json:"deploymentStrategy,omitempty"` diff --git a/pkg/apis/serving/v1beta1/configmap.go b/pkg/apis/serving/v1beta1/configmap.go index 14150e23424..6255f5b3b11 100644 --- a/pkg/apis/serving/v1beta1/configmap.go +++ b/pkg/apis/serving/v1beta1/configmap.go @@ -19,11 +19,14 @@ package v1beta1 import ( "context" "encoding/json" + "errors" "fmt" + "strings" "text/template" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/client-go/kubernetes" "github.com/kserve/kserve/pkg/constants" @@ -31,12 +34,14 @@ import ( // ConfigMap Keys const ( - ExplainerConfigKeyName = "explainers" - IngressConfigKeyName = "ingress" - DeployConfigName = "deploy" - LocalModelConfigName = "localModel" - SecurityConfigName = "security" - ServiceConfigName = "service" + ExplainerConfigKeyName = "explainers" + InferenceServiceConfigKeyName = "inferenceService" + IngressConfigKeyName = "ingress" + DeployConfigName = "deploy" + LocalModelConfigName = "localModel" + SecurityConfigName = "security" + ServiceConfigName = "service" + ResourceConfigName = "resource" ) const ( @@ -45,6 +50,14 @@ const ( DefaultUrlScheme = "http" ) +// Error messages +const ( + ErrKserveIngressGatewayRequired = "invalid ingress config - kserveIngressGateway is required" + ErrInvalidKserveIngressGatewayFormat = "invalid ingress config - kserveIngressGateway should be in the format /" + ErrInvalidKserveIngressGatewayName = "invalid ingress config - kserveIngressGateway gateway name is invalid" + ErrInvalidKserveIngressGatewayNamespace = "invalid ingress config - kserveIngressGateway gateway namespace is invalid" +) + // +kubebuilder:object:generate=false type ExplainerConfig struct { // explainer docker image name @@ -62,10 +75,19 @@ type ExplainersConfig struct { type InferenceServicesConfig struct { // Explainer configurations Explainers ExplainersConfig `json:"explainers"` + // ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative + // revisions + ServiceAnnotationDisallowedList []string `json:"serviceAnnotationDisallowedList,omitempty"` + // ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions + ServiceLabelDisallowedList []string `json:"serviceLabelDisallowedList,omitempty"` + // Resource configurations + Resource ResourceConfig `json:"resource,omitempty"` } // +kubebuilder:object:generate=false type IngressConfig struct { + EnableGatewayAPI bool `json:"enableGatewayApi,omitempty"` + KserveIngressGateway string `json:"kserveIngressGateway,omitempty"` IngressGateway string `json:"ingressGateway,omitempty"` KnativeLocalGatewayService string `json:"knativeLocalGatewayService,omitempty"` LocalGateway string `json:"localGateway,omitempty"` @@ -102,6 +124,15 @@ type LocalModelConfig struct { FSGroup *int64 `json:"fsGroup,omitempty"` JobTTLSecondsAfterFinished *int32 `json:"jobTTLSecondsAfterFinished,omitempty"` ReconcilationFrequencyInSecs *int64 `json:"reconcilationFrequencyInSecs,omitempty"` + DisableVolumeManagement bool `json:"disableVolumeManagement,omitempty"` +} + +// +kubebuilder:object:generate=false +type ResourceConfig struct { + CPULimit string `json:"cpuLimit,omitempty"` + MemoryLimit string `json:"memoryLimit,omitempty"` + CPURequest string `json:"cpuRequest,omitempty"` + MemoryRequest string `json:"memoryRequest,omitempty"` } // +kubebuilder:object:generate=false @@ -117,21 +148,64 @@ type ServiceConfig struct { } func NewInferenceServicesConfig(clientset kubernetes.Interface) (*InferenceServicesConfig, error) { - configMap, err := clientset.CoreV1().ConfigMaps(constants.KServeNamespace).Get(context.TODO(), constants.InferenceServiceConfigMapName, metav1.GetOptions{}) + configMap, err := clientset.CoreV1().ConfigMaps(constants.KServeNamespace).Get( + context.TODO(), constants.InferenceServiceConfigMapName, metav1.GetOptions{}) + if err != nil { return nil, err } icfg := &InferenceServicesConfig{} for _, err := range []error{ getComponentConfig(ExplainerConfigKeyName, configMap, &icfg.Explainers), + getComponentConfig(InferenceServiceConfigKeyName, configMap, &icfg), } { if err != nil { return nil, err } } + + if isvc, ok := configMap.Data[InferenceServiceConfigKeyName]; ok { + errisvc := json.Unmarshal([]byte(isvc), &icfg) + if errisvc != nil { + return nil, fmt.Errorf("unable to parse isvc config json: %w", errisvc) + } + if icfg.ServiceAnnotationDisallowedList == nil { + icfg.ServiceAnnotationDisallowedList = constants.ServiceAnnotationDisallowedList + } else { + icfg.ServiceAnnotationDisallowedList = append( + constants.ServiceAnnotationDisallowedList, + icfg.ServiceAnnotationDisallowedList...) + } + if icfg.ServiceLabelDisallowedList == nil { + icfg.ServiceLabelDisallowedList = constants.RevisionTemplateLabelDisallowedList + } else { + icfg.ServiceLabelDisallowedList = append( + constants.RevisionTemplateLabelDisallowedList, + icfg.ServiceLabelDisallowedList...) + } + } return icfg, nil } +func validateIngressGateway(ingressConfig *IngressConfig) error { + if ingressConfig.KserveIngressGateway == "" { + return errors.New(ErrKserveIngressGatewayRequired) + } + splits := strings.Split(ingressConfig.KserveIngressGateway, "/") + if len(splits) != 2 { + return errors.New(ErrInvalidKserveIngressGatewayFormat) + } + errs := validation.IsDNS1123Label(splits[0]) + if len(errs) != 0 { + return errors.New(ErrInvalidKserveIngressGatewayNamespace) + } + errs = validation.IsDNS1123Label(splits[1]) + if len(errs) != 0 { + return errors.New(ErrInvalidKserveIngressGatewayName) + } + return nil +} + func NewIngressConfig(clientset kubernetes.Interface) (*IngressConfig, error) { configMap, err := clientset.CoreV1().ConfigMaps(constants.KServeNamespace).Get(context.TODO(), constants.InferenceServiceConfigMapName, metav1.GetOptions{}) if err != nil { @@ -143,7 +217,14 @@ func NewIngressConfig(clientset kubernetes.Interface) (*IngressConfig, error) { if err != nil { return nil, fmt.Errorf("unable to parse ingress config json: %w", err) } - + if ingressConfig.EnableGatewayAPI { + if ingressConfig.KserveIngressGateway == "" { + return nil, fmt.Errorf("invalid ingress config - kserveIngressGateway is required") + } + if err := validateIngressGateway(ingressConfig); err != nil { + return nil, err + } + } if ingressConfig.IngressGateway == "" { return nil, fmt.Errorf("invalid ingress config - ingressGateway is required") } diff --git a/pkg/apis/serving/v1beta1/configmap_test.go b/pkg/apis/serving/v1beta1/configmap_test.go index 71e1e53568d..b1ce4571437 100644 --- a/pkg/apis/serving/v1beta1/configmap_test.go +++ b/pkg/apis/serving/v1beta1/configmap_test.go @@ -28,6 +28,7 @@ import ( ) var ( + KserveIngressGateway = "kserve/kserve-ingress-gateway" KnativeIngressGateway = "knative-serving/knative-ingress-gateway" KnativeLocalGatewayService = "test-destination" KnativeLocalGateway = "knative-serving/knative-local-gateway" @@ -37,6 +38,7 @@ var ( AdditionalDomain = "additional-example.com" AdditionalDomainExtra = "additional-example-extra.com" IngressConfigData = fmt.Sprintf(`{ + "kserveIngressGateway" : "%s", "ingressGateway" : "%s", "knativeLocalGatewayService" : "%s", "localGateway" : "%s", @@ -44,11 +46,22 @@ var ( "ingressDomain": "%s", "urlScheme": "https", "additionalIngressDomains": ["%s","%s"] - }`, KnativeIngressGateway, KnativeLocalGatewayService, KnativeLocalGateway, LocalGatewayService, IngressDomain, + }`, KserveIngressGateway, KnativeIngressGateway, KnativeLocalGatewayService, KnativeLocalGateway, LocalGatewayService, IngressDomain, AdditionalDomain, AdditionalDomainExtra) ServiceConfigData = fmt.Sprintf(`{ "serviceClusterIPNone" : %t }`, true) + + ISCVWithData = fmt.Sprintf(`{ + "serviceAnnotationDisallowedList": ["%s","%s"], + "serviceLabelDisallowedList": ["%s","%s"] + }`, "my.custom.annotation/1", "my.custom.annotation/2", + "my.custom.label.1", "my.custom.label.2") + + ISCVNoData = fmt.Sprintf(`{ + "serviceAnnotationDisallowedList": %s, + "serviceLabelDisallowedList": %s + }`, []string{}, []string{}) ) func TestNewInferenceServiceConfig(t *testing.T) { @@ -88,13 +101,14 @@ func TestNewIngressConfigDefaultKnativeService(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace}, Data: map[string]string{ IngressConfigKeyName: fmt.Sprintf(`{ + "kserveIngressGateway" : "%s", "ingressGateway" : "%s", "localGateway" : "%s", "localGatewayService" : "%s", "ingressDomain": "%s", "urlScheme": "https", "additionalIngressDomains": ["%s","%s"] - }`, KnativeIngressGateway, KnativeLocalGateway, LocalGatewayService, IngressDomain, + }`, KserveIngressGateway, KnativeIngressGateway, KnativeLocalGateway, LocalGatewayService, IngressDomain, AdditionalDomain, AdditionalDomainExtra), }, }) @@ -147,5 +161,92 @@ func TestNewServiceConfig(t *testing.T) { g.Expect(err).Should(gomega.BeNil()) g.Expect(nv).ShouldNot(gomega.BeNil()) g.Expect(nv.ServiceClusterIPNone).Should(gomega.BeFalse()) +} + +func TestInferenceServiceDisallowedLists(t *testing.T) { + g := gomega.NewGomegaWithT(t) + withData := fakeclientset.NewSimpleClientset(&v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace}, + Data: map[string]string{ + InferenceServiceConfigKeyName: ISCVWithData, + }, + }) + isvcConfigWithData, err := NewInferenceServicesConfig(withData) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(isvcConfigWithData).ShouldNot(gomega.BeNil()) + + annotations := append(constants.ServiceAnnotationDisallowedList, []string{"my.custom.annotation/1", "my.custom.annotation/2"}...) + g.Expect(isvcConfigWithData.ServiceAnnotationDisallowedList).To(gomega.Equal(annotations)) + labels := append(constants.RevisionTemplateLabelDisallowedList, []string{"my.custom.label.1", "my.custom.label.2"}...) + g.Expect(isvcConfigWithData.ServiceLabelDisallowedList).To(gomega.Equal(labels)) + + // with no data + withoutData := fakeclientset.NewSimpleClientset(&v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace}, + Data: map[string]string{ + InferenceServiceConfigKeyName: ISCVNoData, + }, + }) + isvcConfigWithoutData, err := NewInferenceServicesConfig(withoutData) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(isvcConfigWithoutData).ShouldNot(gomega.BeNil()) + g.Expect(isvcConfigWithoutData.ServiceAnnotationDisallowedList).To(gomega.Equal(constants.ServiceAnnotationDisallowedList)) + g.Expect(isvcConfigWithoutData.ServiceLabelDisallowedList).To(gomega.Equal(constants.RevisionTemplateLabelDisallowedList)) +} +func TestValidateIngressGateway(t *testing.T) { + g := gomega.NewGomegaWithT(t) + tests := []struct { + name string + ingressConfig *IngressConfig + expectedError string + }{ + { + name: "valid ingress gateway", + ingressConfig: &IngressConfig{ + KserveIngressGateway: "kserve/kserve-ingress-gateway", + }, + expectedError: "", + }, + { + name: "missing kserveIngressGateway", + ingressConfig: &IngressConfig{ + KserveIngressGateway: "", + }, + expectedError: ErrKserveIngressGatewayRequired, + }, + { + name: "invalid format for kserveIngressGateway", + ingressConfig: &IngressConfig{ + KserveIngressGateway: "invalid-format", + }, + expectedError: ErrInvalidKserveIngressGatewayFormat, + }, + { + name: "invalid namespace in kserveIngressGateway", + ingressConfig: &IngressConfig{ + KserveIngressGateway: "invalid_namespace/kserve-ingress-gateway", + }, + expectedError: ErrInvalidKserveIngressGatewayNamespace, + }, + { + name: "invalid name in kserveIngressGateway", + ingressConfig: &IngressConfig{ + KserveIngressGateway: "kserve/invalid_name", + }, + expectedError: ErrInvalidKserveIngressGatewayName, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateIngressGateway(tt.ingressConfig) + if tt.expectedError == "" { + g.Expect(err).Should(gomega.BeNil()) + } else { + g.Expect(err).ShouldNot(gomega.BeNil()) + g.Expect(err.Error()).Should(gomega.ContainSubstring(tt.expectedError)) + } + }) + } } diff --git a/pkg/apis/serving/v1beta1/explainer_art.go b/pkg/apis/serving/v1beta1/explainer_art.go index 1bd0b4b6bf4..fbf9c45976b 100644 --- a/pkg/apis/serving/v1beta1/explainer_art.go +++ b/pkg/apis/serving/v1beta1/explainer_art.go @@ -95,7 +95,7 @@ func (s *ARTExplainerSpec) Default(config *InferenceServicesConfig) { if s.RuntimeVersion == nil { s.RuntimeVersion = proto.String(config.Explainers.ARTExplainer.DefaultImageVersion) } - setResourceRequirementDefaults(&s.Resources) + setResourceRequirementDefaults(config, &s.Resources) } func (s *ARTExplainerSpec) GetProtocol() constants.InferenceServiceProtocol { diff --git a/pkg/apis/serving/v1beta1/explainer_custom.go b/pkg/apis/serving/v1beta1/explainer_custom.go index 326d1c846ea..230845e2666 100644 --- a/pkg/apis/serving/v1beta1/explainer_custom.go +++ b/pkg/apis/serving/v1beta1/explainer_custom.go @@ -48,7 +48,7 @@ func (c *CustomExplainer) Default(config *InferenceServicesConfig) { c.Containers = append(c.Containers, v1.Container{}) } c.Containers[0].Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&c.Containers[0].Resources) + setResourceRequirementDefaults(config, &c.Containers[0].Resources) } func (c *CustomExplainer) GetStorageUri() *string { diff --git a/pkg/apis/serving/v1beta1/explainer_custom_test.go b/pkg/apis/serving/v1beta1/explainer_custom_test.go index 3389593f30d..4b65bdafe03 100644 --- a/pkg/apis/serving/v1beta1/explainer_custom_test.go +++ b/pkg/apis/serving/v1beta1/explainer_custom_test.go @@ -32,8 +32,14 @@ func TestCustomExplainerDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) config := InferenceServicesConfig{ Explainers: ExplainersConfig{}, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, } - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } @@ -247,10 +253,6 @@ func TestCustomExplainerIsMMS(t *testing.T) { config := InferenceServicesConfig{ Explainers: ExplainersConfig{}, } - defaultResource = v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("1"), - v1.ResourceMemory: resource.MustParse("2Gi"), - } mmsCase := false scenarios := map[string]struct { spec ExplainerSpec diff --git a/pkg/apis/serving/v1beta1/inference_service_defaults.go b/pkg/apis/serving/v1beta1/inference_service_defaults.go index 2f65c122c1b..fbe74049296 100644 --- a/pkg/apis/serving/v1beta1/inference_service_defaults.go +++ b/pkg/apis/serving/v1beta1/inference_service_defaults.go @@ -40,10 +40,6 @@ import ( ) var ( - defaultResource = v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("1"), - v1.ResourceMemory: resource.MustParse("2Gi"), - } // logger for the mutating webhook. mutatorLogger = logf.Log.WithName("inferenceservice-v1beta1-mutating-webhook") ) @@ -61,20 +57,39 @@ type InferenceServiceDefaulter struct { // +kubebuilder:webhook:path=/mutate-inferenceservices,mutating=true,failurePolicy=fail,groups=serving.kserve.io,resources=inferenceservices,verbs=create;update,versions=v1beta1,name=inferenceservice.kserve-webhook-server.defaulter var _ webhook.CustomDefaulter = &InferenceServiceDefaulter{} -func setResourceRequirementDefaults(requirements *v1.ResourceRequirements) { +func setResourceRequirementDefaults(config *InferenceServicesConfig, requirements *v1.ResourceRequirements) { + var defaultResourceRequests = v1.ResourceList{} + var defaultResourceLimits = v1.ResourceList{} + + if config != nil { + if config.Resource.CPURequest != "" { + defaultResourceRequests[v1.ResourceCPU] = resource.MustParse(config.Resource.CPURequest) + } + if config.Resource.MemoryRequest != "" { + defaultResourceRequests[v1.ResourceMemory] = resource.MustParse(config.Resource.MemoryRequest) + } + if config.Resource.CPULimit != "" { + defaultResourceLimits[v1.ResourceCPU] = resource.MustParse(config.Resource.CPULimit) + } + if config.Resource.MemoryLimit != "" { + defaultResourceLimits[v1.ResourceMemory] = resource.MustParse(config.Resource.MemoryLimit) + } + } if requirements.Requests == nil { requirements.Requests = v1.ResourceList{} } - for k, v := range defaultResource { + for k, v := range defaultResourceRequests { if _, ok := requirements.Requests[k]; !ok { requirements.Requests[k] = v } } + logf.Log.Info("Setting default resource requirements -----------------", "requests", requirements.Requests, "limits", requirements.Limits) + if requirements.Limits == nil { requirements.Limits = v1.ResourceList{} } - for k, v := range defaultResource { + for k, v := range defaultResourceLimits { if _, ok := requirements.Limits[k]; !ok { requirements.Limits[k] = v } diff --git a/pkg/apis/serving/v1beta1/inference_service_defaults_test.go b/pkg/apis/serving/v1beta1/inference_service_defaults_test.go index cc0e7ee2b74..ba7f2659cd0 100644 --- a/pkg/apis/serving/v1beta1/inference_service_defaults_test.go +++ b/pkg/apis/serving/v1beta1/inference_service_defaults_test.go @@ -33,6 +33,10 @@ import ( func TestInferenceServiceDefaults(t *testing.T) { g := gomega.NewGomegaWithT(t) + defaultResource := v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("1"), + v1.ResourceMemory: resource.MustParse("2Gi"), + } scenarios := map[string]struct { config *InferenceServicesConfig deployConfig *DeployConfig @@ -48,6 +52,12 @@ func TestInferenceServiceDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, }, deployConfig: &DeployConfig{ DefaultDeploymentMode: "Serverless", @@ -100,6 +110,12 @@ func TestInferenceServiceDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, }, deployConfig: &DeployConfig{ DefaultDeploymentMode: string(constants.RawDeployment), @@ -152,6 +168,12 @@ func TestInferenceServiceDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, }, deployConfig: &DeployConfig{ DefaultDeploymentMode: "Serverless", @@ -204,6 +226,12 @@ func TestInferenceServiceDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, }, deployConfig: &DeployConfig{ DefaultDeploymentMode: "Serverless", @@ -256,6 +284,12 @@ func TestInferenceServiceDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, }, deployConfig: &DeployConfig{ DefaultDeploymentMode: "Serverless", @@ -319,8 +353,63 @@ func TestInferenceServiceDefaults(t *testing.T) { } } +func TestCustomPredictorDefaultsConfig(t *testing.T) { + expectedResource := v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("2"), + v1.ResourceMemory: resource.MustParse("4Gi"), + } + g := gomega.NewGomegaWithT(t) + config := &InferenceServicesConfig{ + Explainers: ExplainersConfig{ + ARTExplainer: ExplainerConfig{ + ContainerImage: "art", + DefaultImageVersion: "v0.4.0", + }, + }, + Resource: ResourceConfig{ + CPULimit: "2", + MemoryLimit: "4Gi", + CPURequest: "2", + MemoryRequest: "4Gi", + }, + } + deployConfig := &DeployConfig{ + DefaultDeploymentMode: "Serverless", + } + isvc := InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: InferenceServiceSpec{ + Predictor: PredictorSpec{ + PodSpec: PodSpec{ + Containers: []v1.Container{ + { + Env: []v1.EnvVar{ + { + Name: "STORAGE_URI", + Value: "s3://transformer", + }, + }, + }, + }, + }, + }, + }, + } + resources := v1.ResourceRequirements{Requests: expectedResource, Limits: expectedResource} + isvc.Spec.DeepCopy() + isvc.DefaultInferenceService(config, deployConfig, nil, nil) + g.Expect(isvc.Spec.Predictor.PodSpec.Containers[0].Resources).To(gomega.Equal(resources)) +} + func TestCustomPredictorDefaults(t *testing.T) { g := gomega.NewGomegaWithT(t) + var defaultResource = v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("1"), + v1.ResourceMemory: resource.MustParse("2Gi"), + } config := &InferenceServicesConfig{ Explainers: ExplainersConfig{ ARTExplainer: ExplainerConfig{ @@ -328,6 +417,12 @@ func TestCustomPredictorDefaults(t *testing.T) { DefaultImageVersion: "v0.4.0", }, }, + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, } deployConfig := &DeployConfig{ DefaultDeploymentMode: "Serverless", diff --git a/pkg/apis/serving/v1beta1/predictor_custom.go b/pkg/apis/serving/v1beta1/predictor_custom.go index c0dff08620e..0ec310ffc5f 100644 --- a/pkg/apis/serving/v1beta1/predictor_custom.go +++ b/pkg/apis/serving/v1beta1/predictor_custom.go @@ -66,7 +66,7 @@ func (c *CustomPredictor) Default(config *InferenceServicesConfig) { c.Containers = append(c.Containers, v1.Container{}) } c.Containers[0].Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&c.Containers[0].Resources) + setResourceRequirementDefaults(config, &c.Containers[0].Resources) } func (c *CustomPredictor) GetStorageUri() *string { diff --git a/pkg/apis/serving/v1beta1/predictor_custom_test.go b/pkg/apis/serving/v1beta1/predictor_custom_test.go index 7a151a3c6c0..85410b8295b 100644 --- a/pkg/apis/serving/v1beta1/predictor_custom_test.go +++ b/pkg/apis/serving/v1beta1/predictor_custom_test.go @@ -113,10 +113,19 @@ func TestCustomPredictorValidation(t *testing.T) { func TestCustomPredictorDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -161,7 +170,7 @@ func TestCustomPredictorDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { customPredictor := NewCustomPredictor(&scenario.spec.PodSpec) - customPredictor.Default(nil) + customPredictor.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime.go b/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime.go index bc95fbed395..d35798871ed 100644 --- a/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime.go +++ b/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime.go @@ -43,7 +43,7 @@ func (o *HuggingFaceRuntimeSpec) Validate() error { // Default sets defaults on the resource func (o *HuggingFaceRuntimeSpec) Default(config *InferenceServicesConfig) { o.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&o.Resources) + setResourceRequirementDefaults(config, &o.Resources) } // GetContainer transforms the resource into a container spec diff --git a/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime_test.go b/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime_test.go index 357fbff56cc..7aa8f0fa3b7 100644 --- a/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime_test.go +++ b/pkg/apis/serving/v1beta1/predictor_huggingfaceruntime_test.go @@ -60,10 +60,19 @@ func TestHuggingFaceRuntimeValidation(t *testing.T) { func TestHuggingFaceRuntimeDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -95,7 +104,7 @@ func TestHuggingFaceRuntimeDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.HuggingFace.Default(nil) + scenario.spec.HuggingFace.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_lightgbm.go b/pkg/apis/serving/v1beta1/predictor_lightgbm.go index a672f65ae25..248b83fa671 100644 --- a/pkg/apis/serving/v1beta1/predictor_lightgbm.go +++ b/pkg/apis/serving/v1beta1/predictor_lightgbm.go @@ -35,7 +35,7 @@ var ( // Default sets defaults on the resource func (x *LightGBMSpec) Default(config *InferenceServicesConfig) { x.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&x.Resources) + setResourceRequirementDefaults(config, &x.Resources) } func (x *LightGBMSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_lightgbm_test.go b/pkg/apis/serving/v1beta1/predictor_lightgbm_test.go index 1aa19952d66..422eac9a25a 100644 --- a/pkg/apis/serving/v1beta1/predictor_lightgbm_test.go +++ b/pkg/apis/serving/v1beta1/predictor_lightgbm_test.go @@ -60,10 +60,19 @@ func TestLightGBMValidation(t *testing.T) { func TestLightGBMDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -95,7 +104,7 @@ func TestLightGBMDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.LightGBM.Default(nil) + scenario.spec.LightGBM.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_onnxruntime.go b/pkg/apis/serving/v1beta1/predictor_onnxruntime.go index 1dd2c80e3d4..b157f0e555a 100644 --- a/pkg/apis/serving/v1beta1/predictor_onnxruntime.go +++ b/pkg/apis/serving/v1beta1/predictor_onnxruntime.go @@ -56,7 +56,7 @@ func (o *ONNXRuntimeSpec) Validate() error { // Default sets defaults on the resource func (o *ONNXRuntimeSpec) Default(config *InferenceServicesConfig) { o.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&o.Resources) + setResourceRequirementDefaults(config, &o.Resources) } // GetContainers transforms the resource into a container spec diff --git a/pkg/apis/serving/v1beta1/predictor_onnxruntime_test.go b/pkg/apis/serving/v1beta1/predictor_onnxruntime_test.go index b7976517273..454bdca5640 100644 --- a/pkg/apis/serving/v1beta1/predictor_onnxruntime_test.go +++ b/pkg/apis/serving/v1beta1/predictor_onnxruntime_test.go @@ -80,10 +80,19 @@ func TestOnnxRuntimeValidation(t *testing.T) { func TestONNXRuntimeDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -115,7 +124,7 @@ func TestONNXRuntimeDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.ONNX.Default(nil) + scenario.spec.ONNX.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_paddle.go b/pkg/apis/serving/v1beta1/predictor_paddle.go index 6e0000e1658..5ca9b357798 100644 --- a/pkg/apis/serving/v1beta1/predictor_paddle.go +++ b/pkg/apis/serving/v1beta1/predictor_paddle.go @@ -29,7 +29,7 @@ type PaddleServerSpec struct { func (p *PaddleServerSpec) Default(config *InferenceServicesConfig) { // TODO: add GPU support p.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&p.Resources) + setResourceRequirementDefaults(config, &p.Resources) } func (p *PaddleServerSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_paddle_test.go b/pkg/apis/serving/v1beta1/predictor_paddle_test.go index 1aa7c9ebba8..d1e3f553217 100644 --- a/pkg/apis/serving/v1beta1/predictor_paddle_test.go +++ b/pkg/apis/serving/v1beta1/predictor_paddle_test.go @@ -19,6 +19,7 @@ package v1beta1 import ( "testing" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/kserve/kserve/pkg/constants" @@ -59,6 +60,18 @@ func TestPaddleValidation(t *testing.T) { func TestPaddleDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) + defaultResource := v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("1"), + v1.ResourceMemory: resource.MustParse("2Gi"), + } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec PredictorSpec @@ -88,7 +101,7 @@ func TestPaddleDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.Paddle.Default(nil) + scenario.spec.Paddle.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_pmml.go b/pkg/apis/serving/v1beta1/predictor_pmml.go index 6ee0943cece..10f66199634 100644 --- a/pkg/apis/serving/v1beta1/predictor_pmml.go +++ b/pkg/apis/serving/v1beta1/predictor_pmml.go @@ -43,7 +43,7 @@ func (p *PMMLSpec) Validate() error { // Default sets defaults on the resource func (p *PMMLSpec) Default(config *InferenceServicesConfig) { p.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&p.Resources) + setResourceRequirementDefaults(config, &p.Resources) } func (p *PMMLSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_pmml_test.go b/pkg/apis/serving/v1beta1/predictor_pmml_test.go index 3819a707dcb..ba034cb5f9f 100644 --- a/pkg/apis/serving/v1beta1/predictor_pmml_test.go +++ b/pkg/apis/serving/v1beta1/predictor_pmml_test.go @@ -61,10 +61,19 @@ func TestPMMLValidation(t *testing.T) { func TestPMMLDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -96,7 +105,7 @@ func TestPMMLDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.PMML.Default(nil) + scenario.spec.PMML.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_sklearn.go b/pkg/apis/serving/v1beta1/predictor_sklearn.go index 291107fc635..df3c6cdb360 100644 --- a/pkg/apis/serving/v1beta1/predictor_sklearn.go +++ b/pkg/apis/serving/v1beta1/predictor_sklearn.go @@ -43,7 +43,7 @@ func (k *SKLearnSpec) Default(config *InferenceServicesConfig) { k.ProtocolVersion = &defaultProtocol } - setResourceRequirementDefaults(&k.Resources) + setResourceRequirementDefaults(config, &k.Resources) } // nolint: unused diff --git a/pkg/apis/serving/v1beta1/predictor_sklearn_test.go b/pkg/apis/serving/v1beta1/predictor_sklearn_test.go index c2bd41e1b1e..6426527e023 100644 --- a/pkg/apis/serving/v1beta1/predictor_sklearn_test.go +++ b/pkg/apis/serving/v1beta1/predictor_sklearn_test.go @@ -65,10 +65,19 @@ func TestSKLearnDefaulter(t *testing.T) { protocolV1 := constants.ProtocolV1 protocolV2 := constants.ProtocolV2 - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -124,7 +133,7 @@ func TestSKLearnDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.SKLearn.Default(nil) + scenario.spec.SKLearn.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_tfserving.go b/pkg/apis/serving/v1beta1/predictor_tfserving.go index 80ed651934d..4886b2fd7fb 100644 --- a/pkg/apis/serving/v1beta1/predictor_tfserving.go +++ b/pkg/apis/serving/v1beta1/predictor_tfserving.go @@ -71,7 +71,7 @@ func (t *TFServingSpec) validateGPU() error { // Default sets defaults on the resource func (t *TFServingSpec) Default(config *InferenceServicesConfig) { t.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&t.Resources) + setResourceRequirementDefaults(config, &t.Resources) } func (t *TFServingSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_tfserving_test.go b/pkg/apis/serving/v1beta1/predictor_tfserving_test.go index b0ad2897c50..de6678a9a01 100644 --- a/pkg/apis/serving/v1beta1/predictor_tfserving_test.go +++ b/pkg/apis/serving/v1beta1/predictor_tfserving_test.go @@ -86,10 +86,18 @@ func TestTensorflowValidation(t *testing.T) { func TestTensorflowDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec PredictorSpec @@ -122,7 +130,7 @@ func TestTensorflowDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.Tensorflow.Default(nil) + scenario.spec.Tensorflow.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_torchserve.go b/pkg/apis/serving/v1beta1/predictor_torchserve.go index 19dcbbc36f4..b58724b0948 100644 --- a/pkg/apis/serving/v1beta1/predictor_torchserve.go +++ b/pkg/apis/serving/v1beta1/predictor_torchserve.go @@ -74,7 +74,7 @@ func (t *TorchServeSpec) Default(config *InferenceServicesConfig) { defaultProtocol := constants.ProtocolV1 t.ProtocolVersion = &defaultProtocol } - setResourceRequirementDefaults(&t.Resources) + setResourceRequirementDefaults(config, &t.Resources) } func (t *TorchServeSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_torchserve_test.go b/pkg/apis/serving/v1beta1/predictor_torchserve_test.go index 8d905f670d6..e769e5e3209 100644 --- a/pkg/apis/serving/v1beta1/predictor_torchserve_test.go +++ b/pkg/apis/serving/v1beta1/predictor_torchserve_test.go @@ -88,10 +88,18 @@ func TestTorchServeDefaulter(t *testing.T) { protocolV1 := constants.ProtocolV1 - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceMemory: resource.MustParse("2Gi"), v1.ResourceCPU: resource.MustParse("1"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -146,7 +154,7 @@ func TestTorchServeDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.PyTorch.Default(nil) + scenario.spec.PyTorch.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_triton.go b/pkg/apis/serving/v1beta1/predictor_triton.go index 7f4dd9d78a8..f7d43f67aea 100644 --- a/pkg/apis/serving/v1beta1/predictor_triton.go +++ b/pkg/apis/serving/v1beta1/predictor_triton.go @@ -35,7 +35,7 @@ var ( // Default sets defaults on the resource func (t *TritonSpec) Default(config *InferenceServicesConfig) { t.Container.Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&t.Resources) + setResourceRequirementDefaults(config, &t.Resources) } func (t *TritonSpec) GetContainer(metadata metav1.ObjectMeta, extensions *ComponentExtensionSpec, config *InferenceServicesConfig, predictorHost ...string) *v1.Container { diff --git a/pkg/apis/serving/v1beta1/predictor_triton_test.go b/pkg/apis/serving/v1beta1/predictor_triton_test.go index f39744f10fa..861dedde6f7 100644 --- a/pkg/apis/serving/v1beta1/predictor_triton_test.go +++ b/pkg/apis/serving/v1beta1/predictor_triton_test.go @@ -62,10 +62,18 @@ func TestTritonValidation(t *testing.T) { func TestTritonDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -97,7 +105,7 @@ func TestTritonDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.Triton.Default(nil) + scenario.spec.Triton.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } @@ -144,6 +152,14 @@ func TestTritonSpec_GetContainer(t *testing.T) { func TestTritonSpec_Default(t *testing.T) { g := gomega.NewGomegaWithT(t) + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec PredictorSpec expected *TritonSpec @@ -189,7 +205,7 @@ func TestTritonSpec_Default(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.Triton.Default(nil) + scenario.spec.Triton.Default(config) if !g.Expect(scenario.spec.Triton).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec.Triton, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/predictor_xgboost.go b/pkg/apis/serving/v1beta1/predictor_xgboost.go index 1172568d449..2fc1ff70272 100644 --- a/pkg/apis/serving/v1beta1/predictor_xgboost.go +++ b/pkg/apis/serving/v1beta1/predictor_xgboost.go @@ -43,7 +43,7 @@ func (x *XGBoostSpec) Default(config *InferenceServicesConfig) { x.ProtocolVersion = &defaultProtocol } - setResourceRequirementDefaults(&x.Resources) + setResourceRequirementDefaults(config, &x.Resources) } // nolint: unused diff --git a/pkg/apis/serving/v1beta1/predictor_xgboost_test.go b/pkg/apis/serving/v1beta1/predictor_xgboost_test.go index b8739a00735..c3ea9f553ea 100644 --- a/pkg/apis/serving/v1beta1/predictor_xgboost_test.go +++ b/pkg/apis/serving/v1beta1/predictor_xgboost_test.go @@ -65,11 +65,20 @@ func TestXGBoostDefaulter(t *testing.T) { protocolV1 := constants.ProtocolV1 protocolV2 := constants.ProtocolV2 - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } + scenarios := map[string]struct { spec PredictorSpec expected PredictorSpec @@ -148,7 +157,7 @@ func TestXGBoostDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - scenario.spec.XGBoost.Default(nil) + scenario.spec.XGBoost.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/transformer_custom.go b/pkg/apis/serving/v1beta1/transformer_custom.go index 0dbe242b3ec..73104c53fec 100644 --- a/pkg/apis/serving/v1beta1/transformer_custom.go +++ b/pkg/apis/serving/v1beta1/transformer_custom.go @@ -54,7 +54,7 @@ func (c *CustomTransformer) Default(config *InferenceServicesConfig) { c.Containers = append(c.Containers, v1.Container{}) } c.Containers[0].Name = constants.InferenceServiceContainerName - setResourceRequirementDefaults(&c.Containers[0].Resources) + setResourceRequirementDefaults(config, &c.Containers[0].Resources) } func (c *CustomTransformer) GetStorageUri() *string { diff --git a/pkg/apis/serving/v1beta1/transformer_custom_test.go b/pkg/apis/serving/v1beta1/transformer_custom_test.go index b2a6ac42850..055682d382f 100644 --- a/pkg/apis/serving/v1beta1/transformer_custom_test.go +++ b/pkg/apis/serving/v1beta1/transformer_custom_test.go @@ -31,10 +31,18 @@ import ( func TestTransformerDefaulter(t *testing.T) { g := gomega.NewGomegaWithT(t) - defaultResource = v1.ResourceList{ + defaultResource := v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("2Gi"), } + config := &InferenceServicesConfig{ + Resource: ResourceConfig{ + CPULimit: "1", + MemoryLimit: "2Gi", + CPURequest: "1", + MemoryRequest: "2Gi", + }, + } scenarios := map[string]struct { spec TransformerSpec expected TransformerSpec @@ -79,7 +87,7 @@ func TestTransformerDefaulter(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { CustomTransformer := NewCustomTransformer(&scenario.spec.PodSpec) - CustomTransformer.Default(nil) + CustomTransformer.Default(config) if !g.Expect(scenario.spec).To(gomega.Equal(scenario.expected)) { t.Errorf("got %v, want %v", scenario.spec, scenario.expected) } diff --git a/pkg/apis/serving/v1beta1/zz_generated.defaults.go b/pkg/apis/serving/v1beta1/zz_generated.defaults.go index 54778cd8686..be1f3efa0b4 100644 --- a/pkg/apis/serving/v1beta1/zz_generated.defaults.go +++ b/pkg/apis/serving/v1beta1/zz_generated.defaults.go @@ -22,6 +22,7 @@ limitations under the License. package v1beta1 import ( + v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -388,6 +389,51 @@ func SetObjectDefaults_InferenceService(in *InferenceService) { } } if in.Spec.Predictor.WorkerSpec != nil { + for i := range in.Spec.Predictor.WorkerSpec.PodSpec.Volumes { + a := &in.Spec.Predictor.WorkerSpec.PodSpec.Volumes[i] + if a.VolumeSource.ISCSI != nil { + if a.VolumeSource.ISCSI.ISCSIInterface == "" { + a.VolumeSource.ISCSI.ISCSIInterface = "default" + } + } + if a.VolumeSource.RBD != nil { + if a.VolumeSource.RBD.RBDPool == "" { + a.VolumeSource.RBD.RBDPool = "rbd" + } + if a.VolumeSource.RBD.RadosUser == "" { + a.VolumeSource.RBD.RadosUser = "admin" + } + if a.VolumeSource.RBD.Keyring == "" { + a.VolumeSource.RBD.Keyring = "/etc/ceph/keyring" + } + } + if a.VolumeSource.AzureDisk != nil { + if a.VolumeSource.AzureDisk.CachingMode == nil { + ptrVar1 := v1.AzureDataDiskCachingMode(v1.AzureDataDiskCachingReadWrite) + a.VolumeSource.AzureDisk.CachingMode = &ptrVar1 + } + if a.VolumeSource.AzureDisk.FSType == nil { + var ptrVar1 string = "ext4" + a.VolumeSource.AzureDisk.FSType = &ptrVar1 + } + if a.VolumeSource.AzureDisk.ReadOnly == nil { + var ptrVar1 bool = false + a.VolumeSource.AzureDisk.ReadOnly = &ptrVar1 + } + if a.VolumeSource.AzureDisk.Kind == nil { + ptrVar1 := v1.AzureDataDiskKind(v1.AzureSharedBlobDisk) + a.VolumeSource.AzureDisk.Kind = &ptrVar1 + } + } + if a.VolumeSource.ScaleIO != nil { + if a.VolumeSource.ScaleIO.StorageMode == "" { + a.VolumeSource.ScaleIO.StorageMode = "ThinProvisioned" + } + if a.VolumeSource.ScaleIO.FSType == "" { + a.VolumeSource.ScaleIO.FSType = "xfs" + } + } + } for i := range in.Spec.Predictor.WorkerSpec.PodSpec.InitContainers { a := &in.Spec.Predictor.WorkerSpec.PodSpec.InitContainers[i] for j := range a.Ports { @@ -488,6 +534,51 @@ func SetObjectDefaults_InferenceService(in *InferenceService) { } } } + for i := range in.Spec.Predictor.PodSpec.Volumes { + a := &in.Spec.Predictor.PodSpec.Volumes[i] + if a.VolumeSource.ISCSI != nil { + if a.VolumeSource.ISCSI.ISCSIInterface == "" { + a.VolumeSource.ISCSI.ISCSIInterface = "default" + } + } + if a.VolumeSource.RBD != nil { + if a.VolumeSource.RBD.RBDPool == "" { + a.VolumeSource.RBD.RBDPool = "rbd" + } + if a.VolumeSource.RBD.RadosUser == "" { + a.VolumeSource.RBD.RadosUser = "admin" + } + if a.VolumeSource.RBD.Keyring == "" { + a.VolumeSource.RBD.Keyring = "/etc/ceph/keyring" + } + } + if a.VolumeSource.AzureDisk != nil { + if a.VolumeSource.AzureDisk.CachingMode == nil { + ptrVar1 := v1.AzureDataDiskCachingMode(v1.AzureDataDiskCachingReadWrite) + a.VolumeSource.AzureDisk.CachingMode = &ptrVar1 + } + if a.VolumeSource.AzureDisk.FSType == nil { + var ptrVar1 string = "ext4" + a.VolumeSource.AzureDisk.FSType = &ptrVar1 + } + if a.VolumeSource.AzureDisk.ReadOnly == nil { + var ptrVar1 bool = false + a.VolumeSource.AzureDisk.ReadOnly = &ptrVar1 + } + if a.VolumeSource.AzureDisk.Kind == nil { + ptrVar1 := v1.AzureDataDiskKind(v1.AzureSharedBlobDisk) + a.VolumeSource.AzureDisk.Kind = &ptrVar1 + } + } + if a.VolumeSource.ScaleIO != nil { + if a.VolumeSource.ScaleIO.StorageMode == "" { + a.VolumeSource.ScaleIO.StorageMode = "ThinProvisioned" + } + if a.VolumeSource.ScaleIO.FSType == "" { + a.VolumeSource.ScaleIO.FSType = "xfs" + } + } + } for i := range in.Spec.Predictor.PodSpec.InitContainers { a := &in.Spec.Predictor.PodSpec.InitContainers[i] for j := range a.Ports { @@ -620,6 +711,51 @@ func SetObjectDefaults_InferenceService(in *InferenceService) { } } } + for i := range in.Spec.Explainer.PodSpec.Volumes { + a := &in.Spec.Explainer.PodSpec.Volumes[i] + if a.VolumeSource.ISCSI != nil { + if a.VolumeSource.ISCSI.ISCSIInterface == "" { + a.VolumeSource.ISCSI.ISCSIInterface = "default" + } + } + if a.VolumeSource.RBD != nil { + if a.VolumeSource.RBD.RBDPool == "" { + a.VolumeSource.RBD.RBDPool = "rbd" + } + if a.VolumeSource.RBD.RadosUser == "" { + a.VolumeSource.RBD.RadosUser = "admin" + } + if a.VolumeSource.RBD.Keyring == "" { + a.VolumeSource.RBD.Keyring = "/etc/ceph/keyring" + } + } + if a.VolumeSource.AzureDisk != nil { + if a.VolumeSource.AzureDisk.CachingMode == nil { + ptrVar1 := v1.AzureDataDiskCachingMode(v1.AzureDataDiskCachingReadWrite) + a.VolumeSource.AzureDisk.CachingMode = &ptrVar1 + } + if a.VolumeSource.AzureDisk.FSType == nil { + var ptrVar1 string = "ext4" + a.VolumeSource.AzureDisk.FSType = &ptrVar1 + } + if a.VolumeSource.AzureDisk.ReadOnly == nil { + var ptrVar1 bool = false + a.VolumeSource.AzureDisk.ReadOnly = &ptrVar1 + } + if a.VolumeSource.AzureDisk.Kind == nil { + ptrVar1 := v1.AzureDataDiskKind(v1.AzureSharedBlobDisk) + a.VolumeSource.AzureDisk.Kind = &ptrVar1 + } + } + if a.VolumeSource.ScaleIO != nil { + if a.VolumeSource.ScaleIO.StorageMode == "" { + a.VolumeSource.ScaleIO.StorageMode = "ThinProvisioned" + } + if a.VolumeSource.ScaleIO.FSType == "" { + a.VolumeSource.ScaleIO.FSType = "xfs" + } + } + } for i := range in.Spec.Explainer.PodSpec.InitContainers { a := &in.Spec.Explainer.PodSpec.InitContainers[i] for j := range a.Ports { @@ -721,6 +857,51 @@ func SetObjectDefaults_InferenceService(in *InferenceService) { } } if in.Spec.Transformer != nil { + for i := range in.Spec.Transformer.PodSpec.Volumes { + a := &in.Spec.Transformer.PodSpec.Volumes[i] + if a.VolumeSource.ISCSI != nil { + if a.VolumeSource.ISCSI.ISCSIInterface == "" { + a.VolumeSource.ISCSI.ISCSIInterface = "default" + } + } + if a.VolumeSource.RBD != nil { + if a.VolumeSource.RBD.RBDPool == "" { + a.VolumeSource.RBD.RBDPool = "rbd" + } + if a.VolumeSource.RBD.RadosUser == "" { + a.VolumeSource.RBD.RadosUser = "admin" + } + if a.VolumeSource.RBD.Keyring == "" { + a.VolumeSource.RBD.Keyring = "/etc/ceph/keyring" + } + } + if a.VolumeSource.AzureDisk != nil { + if a.VolumeSource.AzureDisk.CachingMode == nil { + ptrVar1 := v1.AzureDataDiskCachingMode(v1.AzureDataDiskCachingReadWrite) + a.VolumeSource.AzureDisk.CachingMode = &ptrVar1 + } + if a.VolumeSource.AzureDisk.FSType == nil { + var ptrVar1 string = "ext4" + a.VolumeSource.AzureDisk.FSType = &ptrVar1 + } + if a.VolumeSource.AzureDisk.ReadOnly == nil { + var ptrVar1 bool = false + a.VolumeSource.AzureDisk.ReadOnly = &ptrVar1 + } + if a.VolumeSource.AzureDisk.Kind == nil { + ptrVar1 := v1.AzureDataDiskKind(v1.AzureSharedBlobDisk) + a.VolumeSource.AzureDisk.Kind = &ptrVar1 + } + } + if a.VolumeSource.ScaleIO != nil { + if a.VolumeSource.ScaleIO.StorageMode == "" { + a.VolumeSource.ScaleIO.StorageMode = "ThinProvisioned" + } + if a.VolumeSource.ScaleIO.FSType == "" { + a.VolumeSource.ScaleIO.FSType = "xfs" + } + } + } for i := range in.Spec.Transformer.PodSpec.InitContainers { a := &in.Spec.Transformer.PodSpec.InitContainers[i] for j := range a.Ports { diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index a66dc0c1548..9b922f4ebc0 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -33,8 +33,12 @@ import ( // NewSimpleClientset returns a clientset that will respond with the provided objects. // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement // for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). func NewSimpleClientset(objects ...runtime.Object) *Clientset { o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) for _, obj := range objects { diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterservingruntime.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterservingruntime.go index c6e8bc2e2aa..1d39be5489b 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterservingruntime.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterservingruntime.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // ClusterServingRuntimesGetter has a method to return a ClusterServingRuntimeInterface. @@ -40,6 +39,7 @@ type ClusterServingRuntimesGetter interface { type ClusterServingRuntimeInterface interface { Create(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.CreateOptions) (*v1alpha1.ClusterServingRuntime, error) Update(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ClusterServingRuntime, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ClusterServingRuntime, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type ClusterServingRuntimeInterface interface { // clusterServingRuntimes implements ClusterServingRuntimeInterface type clusterServingRuntimes struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.ClusterServingRuntime, *v1alpha1.ClusterServingRuntimeList] } // newClusterServingRuntimes returns a ClusterServingRuntimes func newClusterServingRuntimes(c *ServingV1alpha1Client, namespace string) *clusterServingRuntimes { return &clusterServingRuntimes{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.ClusterServingRuntime, *v1alpha1.ClusterServingRuntimeList]( + "clusterservingruntimes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.ClusterServingRuntime { return &v1alpha1.ClusterServingRuntime{} }, + func() *v1alpha1.ClusterServingRuntimeList { return &v1alpha1.ClusterServingRuntimeList{} }), } } - -// Get takes name of the clusterServingRuntime, and returns the corresponding clusterServingRuntime object, and an error if there is any. -func (c *clusterServingRuntimes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterServingRuntime, err error) { - result = &v1alpha1.ClusterServingRuntime{} - err = c.client.Get(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ClusterServingRuntimes that match those selectors. -func (c *clusterServingRuntimes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterServingRuntimeList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ClusterServingRuntimeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested clusterServingRuntimes. -func (c *clusterServingRuntimes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a clusterServingRuntime and creates it. Returns the server's representation of the clusterServingRuntime, and an error, if there is any. -func (c *clusterServingRuntimes) Create(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.CreateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { - result = &v1alpha1.ClusterServingRuntime{} - err = c.client.Post(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterServingRuntime). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a clusterServingRuntime and updates it. Returns the server's representation of the clusterServingRuntime, and an error, if there is any. -func (c *clusterServingRuntimes) Update(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { - result = &v1alpha1.ClusterServingRuntime{} - err = c.client.Put(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - Name(clusterServingRuntime.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterServingRuntime). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *clusterServingRuntimes) UpdateStatus(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { - result = &v1alpha1.ClusterServingRuntime{} - err = c.client.Put(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - Name(clusterServingRuntime.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterServingRuntime). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the clusterServingRuntime and deletes it. Returns an error if one occurs. -func (c *clusterServingRuntimes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *clusterServingRuntimes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("clusterservingruntimes"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched clusterServingRuntime. -func (c *clusterServingRuntimes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterServingRuntime, err error) { - result = &v1alpha1.ClusterServingRuntime{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("clusterservingruntimes"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterstoragecontainer.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterstoragecontainer.go index 3b3cd697530..4a0a9cfa358 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterstoragecontainer.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/clusterstoragecontainer.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // ClusterStorageContainersGetter has a method to return a ClusterStorageContainerInterface. @@ -51,128 +50,18 @@ type ClusterStorageContainerInterface interface { // clusterStorageContainers implements ClusterStorageContainerInterface type clusterStorageContainers struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.ClusterStorageContainer, *v1alpha1.ClusterStorageContainerList] } // newClusterStorageContainers returns a ClusterStorageContainers func newClusterStorageContainers(c *ServingV1alpha1Client, namespace string) *clusterStorageContainers { return &clusterStorageContainers{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.ClusterStorageContainer, *v1alpha1.ClusterStorageContainerList]( + "clusterstoragecontainers", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.ClusterStorageContainer { return &v1alpha1.ClusterStorageContainer{} }, + func() *v1alpha1.ClusterStorageContainerList { return &v1alpha1.ClusterStorageContainerList{} }), } } - -// Get takes name of the clusterStorageContainer, and returns the corresponding clusterStorageContainer object, and an error if there is any. -func (c *clusterStorageContainers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterStorageContainer, err error) { - result = &v1alpha1.ClusterStorageContainer{} - err = c.client.Get(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ClusterStorageContainers that match those selectors. -func (c *clusterStorageContainers) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterStorageContainerList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ClusterStorageContainerList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested clusterStorageContainers. -func (c *clusterStorageContainers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a clusterStorageContainer and creates it. Returns the server's representation of the clusterStorageContainer, and an error, if there is any. -func (c *clusterStorageContainers) Create(ctx context.Context, clusterStorageContainer *v1alpha1.ClusterStorageContainer, opts v1.CreateOptions) (result *v1alpha1.ClusterStorageContainer, err error) { - result = &v1alpha1.ClusterStorageContainer{} - err = c.client.Post(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterStorageContainer). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a clusterStorageContainer and updates it. Returns the server's representation of the clusterStorageContainer, and an error, if there is any. -func (c *clusterStorageContainers) Update(ctx context.Context, clusterStorageContainer *v1alpha1.ClusterStorageContainer, opts v1.UpdateOptions) (result *v1alpha1.ClusterStorageContainer, err error) { - result = &v1alpha1.ClusterStorageContainer{} - err = c.client.Put(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - Name(clusterStorageContainer.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterStorageContainer). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the clusterStorageContainer and deletes it. Returns an error if one occurs. -func (c *clusterStorageContainers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *clusterStorageContainers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched clusterStorageContainer. -func (c *clusterStorageContainers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterStorageContainer, err error) { - result = &v1alpha1.ClusterStorageContainer{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("clusterstoragecontainers"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterservingruntime.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterservingruntime.go index b4b75e2438a..11d93573d01 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterservingruntime.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterservingruntime.go @@ -41,22 +41,24 @@ var clusterservingruntimesKind = v1alpha1.SchemeGroupVersion.WithKind("ClusterSe // Get takes name of the clusterServingRuntime, and returns the corresponding clusterServingRuntime object, and an error if there is any. func (c *FakeClusterServingRuntimes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterServingRuntime, err error) { + emptyResult := &v1alpha1.ClusterServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewGetAction(clusterservingruntimesResource, c.ns, name), &v1alpha1.ClusterServingRuntime{}) + Invokes(testing.NewGetActionWithOptions(clusterservingruntimesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterServingRuntime), err } // List takes label and field selectors, and returns the list of ClusterServingRuntimes that match those selectors. func (c *FakeClusterServingRuntimes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterServingRuntimeList, err error) { + emptyResult := &v1alpha1.ClusterServingRuntimeList{} obj, err := c.Fake. - Invokes(testing.NewListAction(clusterservingruntimesResource, clusterservingruntimesKind, c.ns, opts), &v1alpha1.ClusterServingRuntimeList{}) + Invokes(testing.NewListActionWithOptions(clusterservingruntimesResource, clusterservingruntimesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeClusterServingRuntimes) List(ctx context.Context, opts v1.ListOptio // Watch returns a watch.Interface that watches the requested clusterServingRuntimes. func (c *FakeClusterServingRuntimes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(clusterservingruntimesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(clusterservingruntimesResource, c.ns, opts)) } // Create takes the representation of a clusterServingRuntime and creates it. Returns the server's representation of the clusterServingRuntime, and an error, if there is any. func (c *FakeClusterServingRuntimes) Create(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.CreateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { + emptyResult := &v1alpha1.ClusterServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(clusterservingruntimesResource, c.ns, clusterServingRuntime), &v1alpha1.ClusterServingRuntime{}) + Invokes(testing.NewCreateActionWithOptions(clusterservingruntimesResource, c.ns, clusterServingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterServingRuntime), err } // Update takes the representation of a clusterServingRuntime and updates it. Returns the server's representation of the clusterServingRuntime, and an error, if there is any. func (c *FakeClusterServingRuntimes) Update(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { + emptyResult := &v1alpha1.ClusterServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(clusterservingruntimesResource, c.ns, clusterServingRuntime), &v1alpha1.ClusterServingRuntime{}) + Invokes(testing.NewUpdateActionWithOptions(clusterservingruntimesResource, c.ns, clusterServingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterServingRuntime), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeClusterServingRuntimes) UpdateStatus(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ClusterServingRuntime, error) { +func (c *FakeClusterServingRuntimes) UpdateStatus(ctx context.Context, clusterServingRuntime *v1alpha1.ClusterServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ClusterServingRuntime, err error) { + emptyResult := &v1alpha1.ClusterServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(clusterservingruntimesResource, "status", c.ns, clusterServingRuntime), &v1alpha1.ClusterServingRuntime{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(clusterservingruntimesResource, "status", c.ns, clusterServingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterServingRuntime), err } @@ -123,7 +128,7 @@ func (c *FakeClusterServingRuntimes) Delete(ctx context.Context, name string, op // DeleteCollection deletes a collection of objects. func (c *FakeClusterServingRuntimes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(clusterservingruntimesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(clusterservingruntimesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ClusterServingRuntimeList{}) return err @@ -131,11 +136,12 @@ func (c *FakeClusterServingRuntimes) DeleteCollection(ctx context.Context, opts // Patch applies the patch and returns the patched clusterServingRuntime. func (c *FakeClusterServingRuntimes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterServingRuntime, err error) { + emptyResult := &v1alpha1.ClusterServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(clusterservingruntimesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ClusterServingRuntime{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(clusterservingruntimesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterServingRuntime), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterstoragecontainer.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterstoragecontainer.go index fbbe6ef7d88..a5a77e74204 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterstoragecontainer.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_clusterstoragecontainer.go @@ -41,22 +41,24 @@ var clusterstoragecontainersKind = v1alpha1.SchemeGroupVersion.WithKind("Cluster // Get takes name of the clusterStorageContainer, and returns the corresponding clusterStorageContainer object, and an error if there is any. func (c *FakeClusterStorageContainers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterStorageContainer, err error) { + emptyResult := &v1alpha1.ClusterStorageContainer{} obj, err := c.Fake. - Invokes(testing.NewGetAction(clusterstoragecontainersResource, c.ns, name), &v1alpha1.ClusterStorageContainer{}) + Invokes(testing.NewGetActionWithOptions(clusterstoragecontainersResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterStorageContainer), err } // List takes label and field selectors, and returns the list of ClusterStorageContainers that match those selectors. func (c *FakeClusterStorageContainers) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterStorageContainerList, err error) { + emptyResult := &v1alpha1.ClusterStorageContainerList{} obj, err := c.Fake. - Invokes(testing.NewListAction(clusterstoragecontainersResource, clusterstoragecontainersKind, c.ns, opts), &v1alpha1.ClusterStorageContainerList{}) + Invokes(testing.NewListActionWithOptions(clusterstoragecontainersResource, clusterstoragecontainersKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,28 +77,30 @@ func (c *FakeClusterStorageContainers) List(ctx context.Context, opts v1.ListOpt // Watch returns a watch.Interface that watches the requested clusterStorageContainers. func (c *FakeClusterStorageContainers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(clusterstoragecontainersResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(clusterstoragecontainersResource, c.ns, opts)) } // Create takes the representation of a clusterStorageContainer and creates it. Returns the server's representation of the clusterStorageContainer, and an error, if there is any. func (c *FakeClusterStorageContainers) Create(ctx context.Context, clusterStorageContainer *v1alpha1.ClusterStorageContainer, opts v1.CreateOptions) (result *v1alpha1.ClusterStorageContainer, err error) { + emptyResult := &v1alpha1.ClusterStorageContainer{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(clusterstoragecontainersResource, c.ns, clusterStorageContainer), &v1alpha1.ClusterStorageContainer{}) + Invokes(testing.NewCreateActionWithOptions(clusterstoragecontainersResource, c.ns, clusterStorageContainer, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterStorageContainer), err } // Update takes the representation of a clusterStorageContainer and updates it. Returns the server's representation of the clusterStorageContainer, and an error, if there is any. func (c *FakeClusterStorageContainers) Update(ctx context.Context, clusterStorageContainer *v1alpha1.ClusterStorageContainer, opts v1.UpdateOptions) (result *v1alpha1.ClusterStorageContainer, err error) { + emptyResult := &v1alpha1.ClusterStorageContainer{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(clusterstoragecontainersResource, c.ns, clusterStorageContainer), &v1alpha1.ClusterStorageContainer{}) + Invokes(testing.NewUpdateActionWithOptions(clusterstoragecontainersResource, c.ns, clusterStorageContainer, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterStorageContainer), err } @@ -111,7 +115,7 @@ func (c *FakeClusterStorageContainers) Delete(ctx context.Context, name string, // DeleteCollection deletes a collection of objects. func (c *FakeClusterStorageContainers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(clusterstoragecontainersResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(clusterstoragecontainersResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ClusterStorageContainerList{}) return err @@ -119,11 +123,12 @@ func (c *FakeClusterStorageContainers) DeleteCollection(ctx context.Context, opt // Patch applies the patch and returns the patched clusterStorageContainer. func (c *FakeClusterStorageContainers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterStorageContainer, err error) { + emptyResult := &v1alpha1.ClusterStorageContainer{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(clusterstoragecontainersResource, c.ns, name, pt, data, subresources...), &v1alpha1.ClusterStorageContainer{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(clusterstoragecontainersResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterStorageContainer), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_inferencegraph.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_inferencegraph.go index aeaf9b8c375..a727a313a69 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_inferencegraph.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_inferencegraph.go @@ -41,22 +41,24 @@ var inferencegraphsKind = v1alpha1.SchemeGroupVersion.WithKind("InferenceGraph") // Get takes name of the inferenceGraph, and returns the corresponding inferenceGraph object, and an error if there is any. func (c *FakeInferenceGraphs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.InferenceGraph, err error) { + emptyResult := &v1alpha1.InferenceGraph{} obj, err := c.Fake. - Invokes(testing.NewGetAction(inferencegraphsResource, c.ns, name), &v1alpha1.InferenceGraph{}) + Invokes(testing.NewGetActionWithOptions(inferencegraphsResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.InferenceGraph), err } // List takes label and field selectors, and returns the list of InferenceGraphs that match those selectors. func (c *FakeInferenceGraphs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.InferenceGraphList, err error) { + emptyResult := &v1alpha1.InferenceGraphList{} obj, err := c.Fake. - Invokes(testing.NewListAction(inferencegraphsResource, inferencegraphsKind, c.ns, opts), &v1alpha1.InferenceGraphList{}) + Invokes(testing.NewListActionWithOptions(inferencegraphsResource, inferencegraphsKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeInferenceGraphs) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested inferenceGraphs. func (c *FakeInferenceGraphs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(inferencegraphsResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(inferencegraphsResource, c.ns, opts)) } // Create takes the representation of a inferenceGraph and creates it. Returns the server's representation of the inferenceGraph, and an error, if there is any. func (c *FakeInferenceGraphs) Create(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.CreateOptions) (result *v1alpha1.InferenceGraph, err error) { + emptyResult := &v1alpha1.InferenceGraph{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(inferencegraphsResource, c.ns, inferenceGraph), &v1alpha1.InferenceGraph{}) + Invokes(testing.NewCreateActionWithOptions(inferencegraphsResource, c.ns, inferenceGraph, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.InferenceGraph), err } // Update takes the representation of a inferenceGraph and updates it. Returns the server's representation of the inferenceGraph, and an error, if there is any. func (c *FakeInferenceGraphs) Update(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (result *v1alpha1.InferenceGraph, err error) { + emptyResult := &v1alpha1.InferenceGraph{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(inferencegraphsResource, c.ns, inferenceGraph), &v1alpha1.InferenceGraph{}) + Invokes(testing.NewUpdateActionWithOptions(inferencegraphsResource, c.ns, inferenceGraph, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.InferenceGraph), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeInferenceGraphs) UpdateStatus(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (*v1alpha1.InferenceGraph, error) { +func (c *FakeInferenceGraphs) UpdateStatus(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (result *v1alpha1.InferenceGraph, err error) { + emptyResult := &v1alpha1.InferenceGraph{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(inferencegraphsResource, "status", c.ns, inferenceGraph), &v1alpha1.InferenceGraph{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(inferencegraphsResource, "status", c.ns, inferenceGraph, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.InferenceGraph), err } @@ -123,7 +128,7 @@ func (c *FakeInferenceGraphs) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeInferenceGraphs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(inferencegraphsResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(inferencegraphsResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.InferenceGraphList{}) return err @@ -131,11 +136,12 @@ func (c *FakeInferenceGraphs) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched inferenceGraph. func (c *FakeInferenceGraphs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.InferenceGraph, err error) { + emptyResult := &v1alpha1.InferenceGraph{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(inferencegraphsResource, c.ns, name, pt, data, subresources...), &v1alpha1.InferenceGraph{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(inferencegraphsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.InferenceGraph), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelcache.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelcache.go index b2bd7c6c2c1..5d6779e2299 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelcache.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelcache.go @@ -41,22 +41,24 @@ var localmodelcachesKind = v1alpha1.SchemeGroupVersion.WithKind("LocalModelCache // Get takes name of the localModelCache, and returns the corresponding localModelCache object, and an error if there is any. func (c *FakeLocalModelCaches) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelCache, err error) { + emptyResult := &v1alpha1.LocalModelCache{} obj, err := c.Fake. - Invokes(testing.NewGetAction(localmodelcachesResource, c.ns, name), &v1alpha1.LocalModelCache{}) + Invokes(testing.NewGetActionWithOptions(localmodelcachesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelCache), err } // List takes label and field selectors, and returns the list of LocalModelCaches that match those selectors. func (c *FakeLocalModelCaches) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelCacheList, err error) { + emptyResult := &v1alpha1.LocalModelCacheList{} obj, err := c.Fake. - Invokes(testing.NewListAction(localmodelcachesResource, localmodelcachesKind, c.ns, opts), &v1alpha1.LocalModelCacheList{}) + Invokes(testing.NewListActionWithOptions(localmodelcachesResource, localmodelcachesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeLocalModelCaches) List(ctx context.Context, opts v1.ListOptions) (r // Watch returns a watch.Interface that watches the requested localModelCaches. func (c *FakeLocalModelCaches) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(localmodelcachesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(localmodelcachesResource, c.ns, opts)) } // Create takes the representation of a localModelCache and creates it. Returns the server's representation of the localModelCache, and an error, if there is any. func (c *FakeLocalModelCaches) Create(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.CreateOptions) (result *v1alpha1.LocalModelCache, err error) { + emptyResult := &v1alpha1.LocalModelCache{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(localmodelcachesResource, c.ns, localModelCache), &v1alpha1.LocalModelCache{}) + Invokes(testing.NewCreateActionWithOptions(localmodelcachesResource, c.ns, localModelCache, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelCache), err } // Update takes the representation of a localModelCache and updates it. Returns the server's representation of the localModelCache, and an error, if there is any. func (c *FakeLocalModelCaches) Update(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (result *v1alpha1.LocalModelCache, err error) { + emptyResult := &v1alpha1.LocalModelCache{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(localmodelcachesResource, c.ns, localModelCache), &v1alpha1.LocalModelCache{}) + Invokes(testing.NewUpdateActionWithOptions(localmodelcachesResource, c.ns, localModelCache, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelCache), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeLocalModelCaches) UpdateStatus(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (*v1alpha1.LocalModelCache, error) { +func (c *FakeLocalModelCaches) UpdateStatus(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (result *v1alpha1.LocalModelCache, err error) { + emptyResult := &v1alpha1.LocalModelCache{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(localmodelcachesResource, "status", c.ns, localModelCache), &v1alpha1.LocalModelCache{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(localmodelcachesResource, "status", c.ns, localModelCache, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelCache), err } @@ -123,7 +128,7 @@ func (c *FakeLocalModelCaches) Delete(ctx context.Context, name string, opts v1. // DeleteCollection deletes a collection of objects. func (c *FakeLocalModelCaches) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(localmodelcachesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(localmodelcachesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.LocalModelCacheList{}) return err @@ -131,11 +136,12 @@ func (c *FakeLocalModelCaches) DeleteCollection(ctx context.Context, opts v1.Del // Patch applies the patch and returns the patched localModelCache. func (c *FakeLocalModelCaches) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelCache, err error) { + emptyResult := &v1alpha1.LocalModelCache{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localmodelcachesResource, c.ns, name, pt, data, subresources...), &v1alpha1.LocalModelCache{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localmodelcachesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelCache), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnode.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnode.go index c0a64c469dc..7aa6f8a958c 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnode.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnode.go @@ -41,22 +41,24 @@ var localmodelnodesKind = v1alpha1.SchemeGroupVersion.WithKind("LocalModelNode") // Get takes name of the localModelNode, and returns the corresponding localModelNode object, and an error if there is any. func (c *FakeLocalModelNodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelNode, err error) { + emptyResult := &v1alpha1.LocalModelNode{} obj, err := c.Fake. - Invokes(testing.NewGetAction(localmodelnodesResource, c.ns, name), &v1alpha1.LocalModelNode{}) + Invokes(testing.NewGetActionWithOptions(localmodelnodesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNode), err } // List takes label and field selectors, and returns the list of LocalModelNodes that match those selectors. func (c *FakeLocalModelNodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelNodeList, err error) { + emptyResult := &v1alpha1.LocalModelNodeList{} obj, err := c.Fake. - Invokes(testing.NewListAction(localmodelnodesResource, localmodelnodesKind, c.ns, opts), &v1alpha1.LocalModelNodeList{}) + Invokes(testing.NewListActionWithOptions(localmodelnodesResource, localmodelnodesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeLocalModelNodes) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested localModelNodes. func (c *FakeLocalModelNodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(localmodelnodesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(localmodelnodesResource, c.ns, opts)) } // Create takes the representation of a localModelNode and creates it. Returns the server's representation of the localModelNode, and an error, if there is any. func (c *FakeLocalModelNodes) Create(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.CreateOptions) (result *v1alpha1.LocalModelNode, err error) { + emptyResult := &v1alpha1.LocalModelNode{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(localmodelnodesResource, c.ns, localModelNode), &v1alpha1.LocalModelNode{}) + Invokes(testing.NewCreateActionWithOptions(localmodelnodesResource, c.ns, localModelNode, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNode), err } // Update takes the representation of a localModelNode and updates it. Returns the server's representation of the localModelNode, and an error, if there is any. func (c *FakeLocalModelNodes) Update(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNode, err error) { + emptyResult := &v1alpha1.LocalModelNode{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(localmodelnodesResource, c.ns, localModelNode), &v1alpha1.LocalModelNode{}) + Invokes(testing.NewUpdateActionWithOptions(localmodelnodesResource, c.ns, localModelNode, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNode), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeLocalModelNodes) UpdateStatus(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (*v1alpha1.LocalModelNode, error) { +func (c *FakeLocalModelNodes) UpdateStatus(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNode, err error) { + emptyResult := &v1alpha1.LocalModelNode{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(localmodelnodesResource, "status", c.ns, localModelNode), &v1alpha1.LocalModelNode{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(localmodelnodesResource, "status", c.ns, localModelNode, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNode), err } @@ -123,7 +128,7 @@ func (c *FakeLocalModelNodes) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeLocalModelNodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(localmodelnodesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(localmodelnodesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.LocalModelNodeList{}) return err @@ -131,11 +136,12 @@ func (c *FakeLocalModelNodes) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched localModelNode. func (c *FakeLocalModelNodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelNode, err error) { + emptyResult := &v1alpha1.LocalModelNode{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localmodelnodesResource, c.ns, name, pt, data, subresources...), &v1alpha1.LocalModelNode{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localmodelnodesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNode), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnodegroup.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnodegroup.go index 41d7b43cdfc..38223e9dd35 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnodegroup.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_localmodelnodegroup.go @@ -41,22 +41,24 @@ var localmodelnodegroupsKind = v1alpha1.SchemeGroupVersion.WithKind("LocalModelN // Get takes name of the localModelNodeGroup, and returns the corresponding localModelNodeGroup object, and an error if there is any. func (c *FakeLocalModelNodeGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroup{} obj, err := c.Fake. - Invokes(testing.NewGetAction(localmodelnodegroupsResource, c.ns, name), &v1alpha1.LocalModelNodeGroup{}) + Invokes(testing.NewGetActionWithOptions(localmodelnodegroupsResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNodeGroup), err } // List takes label and field selectors, and returns the list of LocalModelNodeGroups that match those selectors. func (c *FakeLocalModelNodeGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelNodeGroupList, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroupList{} obj, err := c.Fake. - Invokes(testing.NewListAction(localmodelnodegroupsResource, localmodelnodegroupsKind, c.ns, opts), &v1alpha1.LocalModelNodeGroupList{}) + Invokes(testing.NewListActionWithOptions(localmodelnodegroupsResource, localmodelnodegroupsKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeLocalModelNodeGroups) List(ctx context.Context, opts v1.ListOptions // Watch returns a watch.Interface that watches the requested localModelNodeGroups. func (c *FakeLocalModelNodeGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(localmodelnodegroupsResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(localmodelnodegroupsResource, c.ns, opts)) } // Create takes the representation of a localModelNodeGroup and creates it. Returns the server's representation of the localModelNodeGroup, and an error, if there is any. func (c *FakeLocalModelNodeGroups) Create(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.CreateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroup{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(localmodelnodegroupsResource, c.ns, localModelNodeGroup), &v1alpha1.LocalModelNodeGroup{}) + Invokes(testing.NewCreateActionWithOptions(localmodelnodegroupsResource, c.ns, localModelNodeGroup, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNodeGroup), err } // Update takes the representation of a localModelNodeGroup and updates it. Returns the server's representation of the localModelNodeGroup, and an error, if there is any. func (c *FakeLocalModelNodeGroups) Update(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroup{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(localmodelnodegroupsResource, c.ns, localModelNodeGroup), &v1alpha1.LocalModelNodeGroup{}) + Invokes(testing.NewUpdateActionWithOptions(localmodelnodegroupsResource, c.ns, localModelNodeGroup, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNodeGroup), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeLocalModelNodeGroups) UpdateStatus(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (*v1alpha1.LocalModelNodeGroup, error) { +func (c *FakeLocalModelNodeGroups) UpdateStatus(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroup{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(localmodelnodegroupsResource, "status", c.ns, localModelNodeGroup), &v1alpha1.LocalModelNodeGroup{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(localmodelnodegroupsResource, "status", c.ns, localModelNodeGroup, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNodeGroup), err } @@ -123,7 +128,7 @@ func (c *FakeLocalModelNodeGroups) Delete(ctx context.Context, name string, opts // DeleteCollection deletes a collection of objects. func (c *FakeLocalModelNodeGroups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(localmodelnodegroupsResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(localmodelnodegroupsResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.LocalModelNodeGroupList{}) return err @@ -131,11 +136,12 @@ func (c *FakeLocalModelNodeGroups) DeleteCollection(ctx context.Context, opts v1 // Patch applies the patch and returns the patched localModelNodeGroup. func (c *FakeLocalModelNodeGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelNodeGroup, err error) { + emptyResult := &v1alpha1.LocalModelNodeGroup{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localmodelnodegroupsResource, c.ns, name, pt, data, subresources...), &v1alpha1.LocalModelNodeGroup{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localmodelnodegroupsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalModelNodeGroup), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_servingruntime.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_servingruntime.go index b311bf1ce7a..cb81825449c 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_servingruntime.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_servingruntime.go @@ -41,22 +41,24 @@ var servingruntimesKind = v1alpha1.SchemeGroupVersion.WithKind("ServingRuntime") // Get takes name of the servingRuntime, and returns the corresponding servingRuntime object, and an error if there is any. func (c *FakeServingRuntimes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ServingRuntime, err error) { + emptyResult := &v1alpha1.ServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewGetAction(servingruntimesResource, c.ns, name), &v1alpha1.ServingRuntime{}) + Invokes(testing.NewGetActionWithOptions(servingruntimesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ServingRuntime), err } // List takes label and field selectors, and returns the list of ServingRuntimes that match those selectors. func (c *FakeServingRuntimes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ServingRuntimeList, err error) { + emptyResult := &v1alpha1.ServingRuntimeList{} obj, err := c.Fake. - Invokes(testing.NewListAction(servingruntimesResource, servingruntimesKind, c.ns, opts), &v1alpha1.ServingRuntimeList{}) + Invokes(testing.NewListActionWithOptions(servingruntimesResource, servingruntimesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeServingRuntimes) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested servingRuntimes. func (c *FakeServingRuntimes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(servingruntimesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(servingruntimesResource, c.ns, opts)) } // Create takes the representation of a servingRuntime and creates it. Returns the server's representation of the servingRuntime, and an error, if there is any. func (c *FakeServingRuntimes) Create(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.CreateOptions) (result *v1alpha1.ServingRuntime, err error) { + emptyResult := &v1alpha1.ServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(servingruntimesResource, c.ns, servingRuntime), &v1alpha1.ServingRuntime{}) + Invokes(testing.NewCreateActionWithOptions(servingruntimesResource, c.ns, servingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ServingRuntime), err } // Update takes the representation of a servingRuntime and updates it. Returns the server's representation of the servingRuntime, and an error, if there is any. func (c *FakeServingRuntimes) Update(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ServingRuntime, err error) { + emptyResult := &v1alpha1.ServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(servingruntimesResource, c.ns, servingRuntime), &v1alpha1.ServingRuntime{}) + Invokes(testing.NewUpdateActionWithOptions(servingruntimesResource, c.ns, servingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ServingRuntime), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeServingRuntimes) UpdateStatus(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ServingRuntime, error) { +func (c *FakeServingRuntimes) UpdateStatus(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ServingRuntime, err error) { + emptyResult := &v1alpha1.ServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(servingruntimesResource, "status", c.ns, servingRuntime), &v1alpha1.ServingRuntime{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(servingruntimesResource, "status", c.ns, servingRuntime, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ServingRuntime), err } @@ -123,7 +128,7 @@ func (c *FakeServingRuntimes) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeServingRuntimes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(servingruntimesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(servingruntimesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ServingRuntimeList{}) return err @@ -131,11 +136,12 @@ func (c *FakeServingRuntimes) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched servingRuntime. func (c *FakeServingRuntimes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ServingRuntime, err error) { + emptyResult := &v1alpha1.ServingRuntime{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(servingruntimesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ServingRuntime{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(servingruntimesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ServingRuntime), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_trainedmodel.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_trainedmodel.go index ed2511cb248..736f5b01166 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_trainedmodel.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_trainedmodel.go @@ -41,22 +41,24 @@ var trainedmodelsKind = v1alpha1.SchemeGroupVersion.WithKind("TrainedModel") // Get takes name of the trainedModel, and returns the corresponding trainedModel object, and an error if there is any. func (c *FakeTrainedModels) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrainedModel, err error) { + emptyResult := &v1alpha1.TrainedModel{} obj, err := c.Fake. - Invokes(testing.NewGetAction(trainedmodelsResource, c.ns, name), &v1alpha1.TrainedModel{}) + Invokes(testing.NewGetActionWithOptions(trainedmodelsResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.TrainedModel), err } // List takes label and field selectors, and returns the list of TrainedModels that match those selectors. func (c *FakeTrainedModels) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrainedModelList, err error) { + emptyResult := &v1alpha1.TrainedModelList{} obj, err := c.Fake. - Invokes(testing.NewListAction(trainedmodelsResource, trainedmodelsKind, c.ns, opts), &v1alpha1.TrainedModelList{}) + Invokes(testing.NewListActionWithOptions(trainedmodelsResource, trainedmodelsKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeTrainedModels) List(ctx context.Context, opts v1.ListOptions) (resu // Watch returns a watch.Interface that watches the requested trainedModels. func (c *FakeTrainedModels) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(trainedmodelsResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(trainedmodelsResource, c.ns, opts)) } // Create takes the representation of a trainedModel and creates it. Returns the server's representation of the trainedModel, and an error, if there is any. func (c *FakeTrainedModels) Create(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.CreateOptions) (result *v1alpha1.TrainedModel, err error) { + emptyResult := &v1alpha1.TrainedModel{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(trainedmodelsResource, c.ns, trainedModel), &v1alpha1.TrainedModel{}) + Invokes(testing.NewCreateActionWithOptions(trainedmodelsResource, c.ns, trainedModel, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.TrainedModel), err } // Update takes the representation of a trainedModel and updates it. Returns the server's representation of the trainedModel, and an error, if there is any. func (c *FakeTrainedModels) Update(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (result *v1alpha1.TrainedModel, err error) { + emptyResult := &v1alpha1.TrainedModel{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(trainedmodelsResource, c.ns, trainedModel), &v1alpha1.TrainedModel{}) + Invokes(testing.NewUpdateActionWithOptions(trainedmodelsResource, c.ns, trainedModel, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.TrainedModel), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTrainedModels) UpdateStatus(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (*v1alpha1.TrainedModel, error) { +func (c *FakeTrainedModels) UpdateStatus(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (result *v1alpha1.TrainedModel, err error) { + emptyResult := &v1alpha1.TrainedModel{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(trainedmodelsResource, "status", c.ns, trainedModel), &v1alpha1.TrainedModel{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(trainedmodelsResource, "status", c.ns, trainedModel, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.TrainedModel), err } @@ -123,7 +128,7 @@ func (c *FakeTrainedModels) Delete(ctx context.Context, name string, opts v1.Del // DeleteCollection deletes a collection of objects. func (c *FakeTrainedModels) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(trainedmodelsResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(trainedmodelsResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.TrainedModelList{}) return err @@ -131,11 +136,12 @@ func (c *FakeTrainedModels) DeleteCollection(ctx context.Context, opts v1.Delete // Patch applies the patch and returns the patched trainedModel. func (c *FakeTrainedModels) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrainedModel, err error) { + emptyResult := &v1alpha1.TrainedModel{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(trainedmodelsResource, c.ns, name, pt, data, subresources...), &v1alpha1.TrainedModel{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(trainedmodelsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.TrainedModel), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/inferencegraph.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/inferencegraph.go index 09dd6f439d8..44908ed0189 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/inferencegraph.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/inferencegraph.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // InferenceGraphsGetter has a method to return a InferenceGraphInterface. @@ -40,6 +39,7 @@ type InferenceGraphsGetter interface { type InferenceGraphInterface interface { Create(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.CreateOptions) (*v1alpha1.InferenceGraph, error) Update(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (*v1alpha1.InferenceGraph, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (*v1alpha1.InferenceGraph, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type InferenceGraphInterface interface { // inferenceGraphs implements InferenceGraphInterface type inferenceGraphs struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.InferenceGraph, *v1alpha1.InferenceGraphList] } // newInferenceGraphs returns a InferenceGraphs func newInferenceGraphs(c *ServingV1alpha1Client, namespace string) *inferenceGraphs { return &inferenceGraphs{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.InferenceGraph, *v1alpha1.InferenceGraphList]( + "inferencegraphs", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.InferenceGraph { return &v1alpha1.InferenceGraph{} }, + func() *v1alpha1.InferenceGraphList { return &v1alpha1.InferenceGraphList{} }), } } - -// Get takes name of the inferenceGraph, and returns the corresponding inferenceGraph object, and an error if there is any. -func (c *inferenceGraphs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.InferenceGraph, err error) { - result = &v1alpha1.InferenceGraph{} - err = c.client.Get(). - Namespace(c.ns). - Resource("inferencegraphs"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of InferenceGraphs that match those selectors. -func (c *inferenceGraphs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.InferenceGraphList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.InferenceGraphList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("inferencegraphs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested inferenceGraphs. -func (c *inferenceGraphs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("inferencegraphs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a inferenceGraph and creates it. Returns the server's representation of the inferenceGraph, and an error, if there is any. -func (c *inferenceGraphs) Create(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.CreateOptions) (result *v1alpha1.InferenceGraph, err error) { - result = &v1alpha1.InferenceGraph{} - err = c.client.Post(). - Namespace(c.ns). - Resource("inferencegraphs"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceGraph). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a inferenceGraph and updates it. Returns the server's representation of the inferenceGraph, and an error, if there is any. -func (c *inferenceGraphs) Update(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (result *v1alpha1.InferenceGraph, err error) { - result = &v1alpha1.InferenceGraph{} - err = c.client.Put(). - Namespace(c.ns). - Resource("inferencegraphs"). - Name(inferenceGraph.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceGraph). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *inferenceGraphs) UpdateStatus(ctx context.Context, inferenceGraph *v1alpha1.InferenceGraph, opts v1.UpdateOptions) (result *v1alpha1.InferenceGraph, err error) { - result = &v1alpha1.InferenceGraph{} - err = c.client.Put(). - Namespace(c.ns). - Resource("inferencegraphs"). - Name(inferenceGraph.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceGraph). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the inferenceGraph and deletes it. Returns an error if one occurs. -func (c *inferenceGraphs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("inferencegraphs"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *inferenceGraphs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("inferencegraphs"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched inferenceGraph. -func (c *inferenceGraphs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.InferenceGraph, err error) { - result = &v1alpha1.InferenceGraph{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("inferencegraphs"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelcache.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelcache.go index bf81697bb20..2c010ef1fce 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelcache.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelcache.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // LocalModelCachesGetter has a method to return a LocalModelCacheInterface. @@ -40,6 +39,7 @@ type LocalModelCachesGetter interface { type LocalModelCacheInterface interface { Create(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.CreateOptions) (*v1alpha1.LocalModelCache, error) Update(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (*v1alpha1.LocalModelCache, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (*v1alpha1.LocalModelCache, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type LocalModelCacheInterface interface { // localModelCaches implements LocalModelCacheInterface type localModelCaches struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.LocalModelCache, *v1alpha1.LocalModelCacheList] } // newLocalModelCaches returns a LocalModelCaches func newLocalModelCaches(c *ServingV1alpha1Client, namespace string) *localModelCaches { return &localModelCaches{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.LocalModelCache, *v1alpha1.LocalModelCacheList]( + "localmodelcaches", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.LocalModelCache { return &v1alpha1.LocalModelCache{} }, + func() *v1alpha1.LocalModelCacheList { return &v1alpha1.LocalModelCacheList{} }), } } - -// Get takes name of the localModelCache, and returns the corresponding localModelCache object, and an error if there is any. -func (c *localModelCaches) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelCache, err error) { - result = &v1alpha1.LocalModelCache{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelcaches"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of LocalModelCaches that match those selectors. -func (c *localModelCaches) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelCacheList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.LocalModelCacheList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelcaches"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested localModelCaches. -func (c *localModelCaches) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("localmodelcaches"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a localModelCache and creates it. Returns the server's representation of the localModelCache, and an error, if there is any. -func (c *localModelCaches) Create(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.CreateOptions) (result *v1alpha1.LocalModelCache, err error) { - result = &v1alpha1.LocalModelCache{} - err = c.client.Post(). - Namespace(c.ns). - Resource("localmodelcaches"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelCache). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a localModelCache and updates it. Returns the server's representation of the localModelCache, and an error, if there is any. -func (c *localModelCaches) Update(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (result *v1alpha1.LocalModelCache, err error) { - result = &v1alpha1.LocalModelCache{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelcaches"). - Name(localModelCache.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelCache). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *localModelCaches) UpdateStatus(ctx context.Context, localModelCache *v1alpha1.LocalModelCache, opts v1.UpdateOptions) (result *v1alpha1.LocalModelCache, err error) { - result = &v1alpha1.LocalModelCache{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelcaches"). - Name(localModelCache.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelCache). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the localModelCache and deletes it. Returns an error if one occurs. -func (c *localModelCaches) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelcaches"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *localModelCaches) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelcaches"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched localModelCache. -func (c *localModelCaches) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelCache, err error) { - result = &v1alpha1.LocalModelCache{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("localmodelcaches"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnode.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnode.go index 03fef113abb..6df61e22dd0 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnode.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnode.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // LocalModelNodesGetter has a method to return a LocalModelNodeInterface. @@ -40,6 +39,7 @@ type LocalModelNodesGetter interface { type LocalModelNodeInterface interface { Create(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.CreateOptions) (*v1alpha1.LocalModelNode, error) Update(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (*v1alpha1.LocalModelNode, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (*v1alpha1.LocalModelNode, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type LocalModelNodeInterface interface { // localModelNodes implements LocalModelNodeInterface type localModelNodes struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.LocalModelNode, *v1alpha1.LocalModelNodeList] } // newLocalModelNodes returns a LocalModelNodes func newLocalModelNodes(c *ServingV1alpha1Client, namespace string) *localModelNodes { return &localModelNodes{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.LocalModelNode, *v1alpha1.LocalModelNodeList]( + "localmodelnodes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.LocalModelNode { return &v1alpha1.LocalModelNode{} }, + func() *v1alpha1.LocalModelNodeList { return &v1alpha1.LocalModelNodeList{} }), } } - -// Get takes name of the localModelNode, and returns the corresponding localModelNode object, and an error if there is any. -func (c *localModelNodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelNode, err error) { - result = &v1alpha1.LocalModelNode{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of LocalModelNodes that match those selectors. -func (c *localModelNodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelNodeList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.LocalModelNodeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested localModelNodes. -func (c *localModelNodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a localModelNode and creates it. Returns the server's representation of the localModelNode, and an error, if there is any. -func (c *localModelNodes) Create(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.CreateOptions) (result *v1alpha1.LocalModelNode, err error) { - result = &v1alpha1.LocalModelNode{} - err = c.client.Post(). - Namespace(c.ns). - Resource("localmodelnodes"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNode). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a localModelNode and updates it. Returns the server's representation of the localModelNode, and an error, if there is any. -func (c *localModelNodes) Update(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNode, err error) { - result = &v1alpha1.LocalModelNode{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelnodes"). - Name(localModelNode.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNode). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *localModelNodes) UpdateStatus(ctx context.Context, localModelNode *v1alpha1.LocalModelNode, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNode, err error) { - result = &v1alpha1.LocalModelNode{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelnodes"). - Name(localModelNode.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNode). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the localModelNode and deletes it. Returns an error if one occurs. -func (c *localModelNodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelnodes"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *localModelNodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelnodes"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched localModelNode. -func (c *localModelNodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelNode, err error) { - result = &v1alpha1.LocalModelNode{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("localmodelnodes"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnodegroup.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnodegroup.go index 1d4e471421e..2feae0a4da1 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnodegroup.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/localmodelnodegroup.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // LocalModelNodeGroupsGetter has a method to return a LocalModelNodeGroupInterface. @@ -40,6 +39,7 @@ type LocalModelNodeGroupsGetter interface { type LocalModelNodeGroupInterface interface { Create(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.CreateOptions) (*v1alpha1.LocalModelNodeGroup, error) Update(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (*v1alpha1.LocalModelNodeGroup, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (*v1alpha1.LocalModelNodeGroup, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type LocalModelNodeGroupInterface interface { // localModelNodeGroups implements LocalModelNodeGroupInterface type localModelNodeGroups struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.LocalModelNodeGroup, *v1alpha1.LocalModelNodeGroupList] } // newLocalModelNodeGroups returns a LocalModelNodeGroups func newLocalModelNodeGroups(c *ServingV1alpha1Client, namespace string) *localModelNodeGroups { return &localModelNodeGroups{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.LocalModelNodeGroup, *v1alpha1.LocalModelNodeGroupList]( + "localmodelnodegroups", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.LocalModelNodeGroup { return &v1alpha1.LocalModelNodeGroup{} }, + func() *v1alpha1.LocalModelNodeGroupList { return &v1alpha1.LocalModelNodeGroupList{} }), } } - -// Get takes name of the localModelNodeGroup, and returns the corresponding localModelNodeGroup object, and an error if there is any. -func (c *localModelNodeGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { - result = &v1alpha1.LocalModelNodeGroup{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of LocalModelNodeGroups that match those selectors. -func (c *localModelNodeGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalModelNodeGroupList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.LocalModelNodeGroupList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested localModelNodeGroups. -func (c *localModelNodeGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a localModelNodeGroup and creates it. Returns the server's representation of the localModelNodeGroup, and an error, if there is any. -func (c *localModelNodeGroups) Create(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.CreateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { - result = &v1alpha1.LocalModelNodeGroup{} - err = c.client.Post(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNodeGroup). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a localModelNodeGroup and updates it. Returns the server's representation of the localModelNodeGroup, and an error, if there is any. -func (c *localModelNodeGroups) Update(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { - result = &v1alpha1.LocalModelNodeGroup{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - Name(localModelNodeGroup.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNodeGroup). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *localModelNodeGroups) UpdateStatus(ctx context.Context, localModelNodeGroup *v1alpha1.LocalModelNodeGroup, opts v1.UpdateOptions) (result *v1alpha1.LocalModelNodeGroup, err error) { - result = &v1alpha1.LocalModelNodeGroup{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - Name(localModelNodeGroup.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localModelNodeGroup). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the localModelNodeGroup and deletes it. Returns an error if one occurs. -func (c *localModelNodeGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *localModelNodeGroups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("localmodelnodegroups"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched localModelNodeGroup. -func (c *localModelNodeGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalModelNodeGroup, err error) { - result = &v1alpha1.LocalModelNodeGroup{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("localmodelnodegroups"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/servingruntime.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/servingruntime.go index 252db9821c3..ff74d2a135b 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/servingruntime.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/servingruntime.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // ServingRuntimesGetter has a method to return a ServingRuntimeInterface. @@ -40,6 +39,7 @@ type ServingRuntimesGetter interface { type ServingRuntimeInterface interface { Create(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.CreateOptions) (*v1alpha1.ServingRuntime, error) Update(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ServingRuntime, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (*v1alpha1.ServingRuntime, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type ServingRuntimeInterface interface { // servingRuntimes implements ServingRuntimeInterface type servingRuntimes struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.ServingRuntime, *v1alpha1.ServingRuntimeList] } // newServingRuntimes returns a ServingRuntimes func newServingRuntimes(c *ServingV1alpha1Client, namespace string) *servingRuntimes { return &servingRuntimes{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.ServingRuntime, *v1alpha1.ServingRuntimeList]( + "servingruntimes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.ServingRuntime { return &v1alpha1.ServingRuntime{} }, + func() *v1alpha1.ServingRuntimeList { return &v1alpha1.ServingRuntimeList{} }), } } - -// Get takes name of the servingRuntime, and returns the corresponding servingRuntime object, and an error if there is any. -func (c *servingRuntimes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ServingRuntime, err error) { - result = &v1alpha1.ServingRuntime{} - err = c.client.Get(). - Namespace(c.ns). - Resource("servingruntimes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ServingRuntimes that match those selectors. -func (c *servingRuntimes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ServingRuntimeList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ServingRuntimeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("servingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested servingRuntimes. -func (c *servingRuntimes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("servingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a servingRuntime and creates it. Returns the server's representation of the servingRuntime, and an error, if there is any. -func (c *servingRuntimes) Create(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.CreateOptions) (result *v1alpha1.ServingRuntime, err error) { - result = &v1alpha1.ServingRuntime{} - err = c.client.Post(). - Namespace(c.ns). - Resource("servingruntimes"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(servingRuntime). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a servingRuntime and updates it. Returns the server's representation of the servingRuntime, and an error, if there is any. -func (c *servingRuntimes) Update(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ServingRuntime, err error) { - result = &v1alpha1.ServingRuntime{} - err = c.client.Put(). - Namespace(c.ns). - Resource("servingruntimes"). - Name(servingRuntime.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(servingRuntime). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *servingRuntimes) UpdateStatus(ctx context.Context, servingRuntime *v1alpha1.ServingRuntime, opts v1.UpdateOptions) (result *v1alpha1.ServingRuntime, err error) { - result = &v1alpha1.ServingRuntime{} - err = c.client.Put(). - Namespace(c.ns). - Resource("servingruntimes"). - Name(servingRuntime.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(servingRuntime). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the servingRuntime and deletes it. Returns an error if one occurs. -func (c *servingRuntimes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("servingruntimes"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *servingRuntimes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("servingruntimes"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched servingRuntime. -func (c *servingRuntimes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ServingRuntime, err error) { - result = &v1alpha1.ServingRuntime{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("servingruntimes"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1alpha1/trainedmodel.go b/pkg/client/clientset/versioned/typed/serving/v1alpha1/trainedmodel.go index 8912c92a333..4ad5780f9ef 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1alpha1/trainedmodel.go +++ b/pkg/client/clientset/versioned/typed/serving/v1alpha1/trainedmodel.go @@ -20,14 +20,13 @@ package v1alpha1 import ( "context" - "time" v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // TrainedModelsGetter has a method to return a TrainedModelInterface. @@ -40,6 +39,7 @@ type TrainedModelsGetter interface { type TrainedModelInterface interface { Create(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.CreateOptions) (*v1alpha1.TrainedModel, error) Update(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (*v1alpha1.TrainedModel, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (*v1alpha1.TrainedModel, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type TrainedModelInterface interface { // trainedModels implements TrainedModelInterface type trainedModels struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.TrainedModel, *v1alpha1.TrainedModelList] } // newTrainedModels returns a TrainedModels func newTrainedModels(c *ServingV1alpha1Client, namespace string) *trainedModels { return &trainedModels{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.TrainedModel, *v1alpha1.TrainedModelList]( + "trainedmodels", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.TrainedModel { return &v1alpha1.TrainedModel{} }, + func() *v1alpha1.TrainedModelList { return &v1alpha1.TrainedModelList{} }), } } - -// Get takes name of the trainedModel, and returns the corresponding trainedModel object, and an error if there is any. -func (c *trainedModels) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrainedModel, err error) { - result = &v1alpha1.TrainedModel{} - err = c.client.Get(). - Namespace(c.ns). - Resource("trainedmodels"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TrainedModels that match those selectors. -func (c *trainedModels) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrainedModelList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.TrainedModelList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("trainedmodels"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested trainedModels. -func (c *trainedModels) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("trainedmodels"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a trainedModel and creates it. Returns the server's representation of the trainedModel, and an error, if there is any. -func (c *trainedModels) Create(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.CreateOptions) (result *v1alpha1.TrainedModel, err error) { - result = &v1alpha1.TrainedModel{} - err = c.client.Post(). - Namespace(c.ns). - Resource("trainedmodels"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(trainedModel). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a trainedModel and updates it. Returns the server's representation of the trainedModel, and an error, if there is any. -func (c *trainedModels) Update(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (result *v1alpha1.TrainedModel, err error) { - result = &v1alpha1.TrainedModel{} - err = c.client.Put(). - Namespace(c.ns). - Resource("trainedmodels"). - Name(trainedModel.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(trainedModel). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *trainedModels) UpdateStatus(ctx context.Context, trainedModel *v1alpha1.TrainedModel, opts v1.UpdateOptions) (result *v1alpha1.TrainedModel, err error) { - result = &v1alpha1.TrainedModel{} - err = c.client.Put(). - Namespace(c.ns). - Resource("trainedmodels"). - Name(trainedModel.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(trainedModel). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the trainedModel and deletes it. Returns an error if one occurs. -func (c *trainedModels) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("trainedmodels"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *trainedModels) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("trainedmodels"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched trainedModel. -func (c *trainedModels) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrainedModel, err error) { - result = &v1alpha1.TrainedModel{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("trainedmodels"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/serving/v1beta1/fake/fake_inferenceservice.go b/pkg/client/clientset/versioned/typed/serving/v1beta1/fake/fake_inferenceservice.go index 3b3afa06954..6c45bc0dd28 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1beta1/fake/fake_inferenceservice.go +++ b/pkg/client/clientset/versioned/typed/serving/v1beta1/fake/fake_inferenceservice.go @@ -41,22 +41,24 @@ var inferenceservicesKind = v1beta1.SchemeGroupVersion.WithKind("InferenceServic // Get takes name of the inferenceService, and returns the corresponding inferenceService object, and an error if there is any. func (c *FakeInferenceServices) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.InferenceService, err error) { + emptyResult := &v1beta1.InferenceService{} obj, err := c.Fake. - Invokes(testing.NewGetAction(inferenceservicesResource, c.ns, name), &v1beta1.InferenceService{}) + Invokes(testing.NewGetActionWithOptions(inferenceservicesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.InferenceService), err } // List takes label and field selectors, and returns the list of InferenceServices that match those selectors. func (c *FakeInferenceServices) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.InferenceServiceList, err error) { + emptyResult := &v1beta1.InferenceServiceList{} obj, err := c.Fake. - Invokes(testing.NewListAction(inferenceservicesResource, inferenceservicesKind, c.ns, opts), &v1beta1.InferenceServiceList{}) + Invokes(testing.NewListActionWithOptions(inferenceservicesResource, inferenceservicesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -75,40 +77,43 @@ func (c *FakeInferenceServices) List(ctx context.Context, opts v1.ListOptions) ( // Watch returns a watch.Interface that watches the requested inferenceServices. func (c *FakeInferenceServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(inferenceservicesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(inferenceservicesResource, c.ns, opts)) } // Create takes the representation of a inferenceService and creates it. Returns the server's representation of the inferenceService, and an error, if there is any. func (c *FakeInferenceServices) Create(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.CreateOptions) (result *v1beta1.InferenceService, err error) { + emptyResult := &v1beta1.InferenceService{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(inferenceservicesResource, c.ns, inferenceService), &v1beta1.InferenceService{}) + Invokes(testing.NewCreateActionWithOptions(inferenceservicesResource, c.ns, inferenceService, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.InferenceService), err } // Update takes the representation of a inferenceService and updates it. Returns the server's representation of the inferenceService, and an error, if there is any. func (c *FakeInferenceServices) Update(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (result *v1beta1.InferenceService, err error) { + emptyResult := &v1beta1.InferenceService{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(inferenceservicesResource, c.ns, inferenceService), &v1beta1.InferenceService{}) + Invokes(testing.NewUpdateActionWithOptions(inferenceservicesResource, c.ns, inferenceService, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.InferenceService), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeInferenceServices) UpdateStatus(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (*v1beta1.InferenceService, error) { +func (c *FakeInferenceServices) UpdateStatus(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (result *v1beta1.InferenceService, err error) { + emptyResult := &v1beta1.InferenceService{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(inferenceservicesResource, "status", c.ns, inferenceService), &v1beta1.InferenceService{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(inferenceservicesResource, "status", c.ns, inferenceService, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.InferenceService), err } @@ -123,7 +128,7 @@ func (c *FakeInferenceServices) Delete(ctx context.Context, name string, opts v1 // DeleteCollection deletes a collection of objects. func (c *FakeInferenceServices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(inferenceservicesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(inferenceservicesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.InferenceServiceList{}) return err @@ -131,11 +136,12 @@ func (c *FakeInferenceServices) DeleteCollection(ctx context.Context, opts v1.De // Patch applies the patch and returns the patched inferenceService. func (c *FakeInferenceServices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.InferenceService, err error) { + emptyResult := &v1beta1.InferenceService{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(inferenceservicesResource, c.ns, name, pt, data, subresources...), &v1beta1.InferenceService{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(inferenceservicesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.InferenceService), err } diff --git a/pkg/client/clientset/versioned/typed/serving/v1beta1/inferenceservice.go b/pkg/client/clientset/versioned/typed/serving/v1beta1/inferenceservice.go index 53e1118e530..6822ec595c2 100644 --- a/pkg/client/clientset/versioned/typed/serving/v1beta1/inferenceservice.go +++ b/pkg/client/clientset/versioned/typed/serving/v1beta1/inferenceservice.go @@ -20,14 +20,13 @@ package v1beta1 import ( "context" - "time" v1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1" scheme "github.com/kserve/kserve/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // InferenceServicesGetter has a method to return a InferenceServiceInterface. @@ -40,6 +39,7 @@ type InferenceServicesGetter interface { type InferenceServiceInterface interface { Create(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.CreateOptions) (*v1beta1.InferenceService, error) Update(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (*v1beta1.InferenceService, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (*v1beta1.InferenceService, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -52,144 +52,18 @@ type InferenceServiceInterface interface { // inferenceServices implements InferenceServiceInterface type inferenceServices struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1beta1.InferenceService, *v1beta1.InferenceServiceList] } // newInferenceServices returns a InferenceServices func newInferenceServices(c *ServingV1beta1Client, namespace string) *inferenceServices { return &inferenceServices{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1beta1.InferenceService, *v1beta1.InferenceServiceList]( + "inferenceservices", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1beta1.InferenceService { return &v1beta1.InferenceService{} }, + func() *v1beta1.InferenceServiceList { return &v1beta1.InferenceServiceList{} }), } } - -// Get takes name of the inferenceService, and returns the corresponding inferenceService object, and an error if there is any. -func (c *inferenceServices) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.InferenceService, err error) { - result = &v1beta1.InferenceService{} - err = c.client.Get(). - Namespace(c.ns). - Resource("inferenceservices"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of InferenceServices that match those selectors. -func (c *inferenceServices) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.InferenceServiceList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.InferenceServiceList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("inferenceservices"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested inferenceServices. -func (c *inferenceServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("inferenceservices"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a inferenceService and creates it. Returns the server's representation of the inferenceService, and an error, if there is any. -func (c *inferenceServices) Create(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.CreateOptions) (result *v1beta1.InferenceService, err error) { - result = &v1beta1.InferenceService{} - err = c.client.Post(). - Namespace(c.ns). - Resource("inferenceservices"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceService). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a inferenceService and updates it. Returns the server's representation of the inferenceService, and an error, if there is any. -func (c *inferenceServices) Update(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (result *v1beta1.InferenceService, err error) { - result = &v1beta1.InferenceService{} - err = c.client.Put(). - Namespace(c.ns). - Resource("inferenceservices"). - Name(inferenceService.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceService). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *inferenceServices) UpdateStatus(ctx context.Context, inferenceService *v1beta1.InferenceService, opts v1.UpdateOptions) (result *v1beta1.InferenceService, err error) { - result = &v1beta1.InferenceService{} - err = c.client.Put(). - Namespace(c.ns). - Resource("inferenceservices"). - Name(inferenceService.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(inferenceService). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the inferenceService and deletes it. Returns an error if one occurs. -func (c *inferenceServices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("inferenceservices"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *inferenceServices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("inferenceservices"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched inferenceService. -func (c *inferenceServices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.InferenceService, err error) { - result = &v1beta1.InferenceService{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("inferenceservices"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 428515b4626..6f5e0a25d47 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -228,6 +228,7 @@ type SharedInformerFactory interface { // Start initializes all requested informers. They are handled in goroutines // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. Start(stopCh <-chan struct{}) // Shutdown marks a factory as shutting down. At that point no new diff --git a/pkg/client/listers/serving/v1alpha1/clusterservingruntime.go b/pkg/client/listers/serving/v1alpha1/clusterservingruntime.go index 9f890e099d0..d52d6e48cd8 100644 --- a/pkg/client/listers/serving/v1alpha1/clusterservingruntime.go +++ b/pkg/client/listers/serving/v1alpha1/clusterservingruntime.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type ClusterServingRuntimeLister interface { // clusterServingRuntimeLister implements the ClusterServingRuntimeLister interface. type clusterServingRuntimeLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.ClusterServingRuntime] } // NewClusterServingRuntimeLister returns a new ClusterServingRuntimeLister. func NewClusterServingRuntimeLister(indexer cache.Indexer) ClusterServingRuntimeLister { - return &clusterServingRuntimeLister{indexer: indexer} -} - -// List lists all ClusterServingRuntimes in the indexer. -func (s *clusterServingRuntimeLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterServingRuntime, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ClusterServingRuntime)) - }) - return ret, err + return &clusterServingRuntimeLister{listers.New[*v1alpha1.ClusterServingRuntime](indexer, v1alpha1.Resource("clusterservingruntime"))} } // ClusterServingRuntimes returns an object that can list and get ClusterServingRuntimes. func (s *clusterServingRuntimeLister) ClusterServingRuntimes(namespace string) ClusterServingRuntimeNamespaceLister { - return clusterServingRuntimeNamespaceLister{indexer: s.indexer, namespace: namespace} + return clusterServingRuntimeNamespaceLister{listers.NewNamespaced[*v1alpha1.ClusterServingRuntime](s.ResourceIndexer, namespace)} } // ClusterServingRuntimeNamespaceLister helps list and get ClusterServingRuntimes. @@ -74,26 +66,5 @@ type ClusterServingRuntimeNamespaceLister interface { // clusterServingRuntimeNamespaceLister implements the ClusterServingRuntimeNamespaceLister // interface. type clusterServingRuntimeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all ClusterServingRuntimes in the indexer for a given namespace. -func (s clusterServingRuntimeNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterServingRuntime, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ClusterServingRuntime)) - }) - return ret, err -} - -// Get retrieves the ClusterServingRuntime from the indexer for a given namespace and name. -func (s clusterServingRuntimeNamespaceLister) Get(name string) (*v1alpha1.ClusterServingRuntime, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("clusterservingruntime"), name) - } - return obj.(*v1alpha1.ClusterServingRuntime), nil + listers.ResourceIndexer[*v1alpha1.ClusterServingRuntime] } diff --git a/pkg/client/listers/serving/v1alpha1/clusterstoragecontainer.go b/pkg/client/listers/serving/v1alpha1/clusterstoragecontainer.go index eec27b1bd2c..a2ad1807a12 100644 --- a/pkg/client/listers/serving/v1alpha1/clusterstoragecontainer.go +++ b/pkg/client/listers/serving/v1alpha1/clusterstoragecontainer.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type ClusterStorageContainerLister interface { // clusterStorageContainerLister implements the ClusterStorageContainerLister interface. type clusterStorageContainerLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.ClusterStorageContainer] } // NewClusterStorageContainerLister returns a new ClusterStorageContainerLister. func NewClusterStorageContainerLister(indexer cache.Indexer) ClusterStorageContainerLister { - return &clusterStorageContainerLister{indexer: indexer} -} - -// List lists all ClusterStorageContainers in the indexer. -func (s *clusterStorageContainerLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterStorageContainer, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ClusterStorageContainer)) - }) - return ret, err + return &clusterStorageContainerLister{listers.New[*v1alpha1.ClusterStorageContainer](indexer, v1alpha1.Resource("clusterstoragecontainer"))} } // ClusterStorageContainers returns an object that can list and get ClusterStorageContainers. func (s *clusterStorageContainerLister) ClusterStorageContainers(namespace string) ClusterStorageContainerNamespaceLister { - return clusterStorageContainerNamespaceLister{indexer: s.indexer, namespace: namespace} + return clusterStorageContainerNamespaceLister{listers.NewNamespaced[*v1alpha1.ClusterStorageContainer](s.ResourceIndexer, namespace)} } // ClusterStorageContainerNamespaceLister helps list and get ClusterStorageContainers. @@ -74,26 +66,5 @@ type ClusterStorageContainerNamespaceLister interface { // clusterStorageContainerNamespaceLister implements the ClusterStorageContainerNamespaceLister // interface. type clusterStorageContainerNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all ClusterStorageContainers in the indexer for a given namespace. -func (s clusterStorageContainerNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterStorageContainer, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ClusterStorageContainer)) - }) - return ret, err -} - -// Get retrieves the ClusterStorageContainer from the indexer for a given namespace and name. -func (s clusterStorageContainerNamespaceLister) Get(name string) (*v1alpha1.ClusterStorageContainer, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("clusterstoragecontainer"), name) - } - return obj.(*v1alpha1.ClusterStorageContainer), nil + listers.ResourceIndexer[*v1alpha1.ClusterStorageContainer] } diff --git a/pkg/client/listers/serving/v1alpha1/inferencegraph.go b/pkg/client/listers/serving/v1alpha1/inferencegraph.go index 1f0e5cac814..baf3a536cbe 100644 --- a/pkg/client/listers/serving/v1alpha1/inferencegraph.go +++ b/pkg/client/listers/serving/v1alpha1/inferencegraph.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type InferenceGraphLister interface { // inferenceGraphLister implements the InferenceGraphLister interface. type inferenceGraphLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.InferenceGraph] } // NewInferenceGraphLister returns a new InferenceGraphLister. func NewInferenceGraphLister(indexer cache.Indexer) InferenceGraphLister { - return &inferenceGraphLister{indexer: indexer} -} - -// List lists all InferenceGraphs in the indexer. -func (s *inferenceGraphLister) List(selector labels.Selector) (ret []*v1alpha1.InferenceGraph, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.InferenceGraph)) - }) - return ret, err + return &inferenceGraphLister{listers.New[*v1alpha1.InferenceGraph](indexer, v1alpha1.Resource("inferencegraph"))} } // InferenceGraphs returns an object that can list and get InferenceGraphs. func (s *inferenceGraphLister) InferenceGraphs(namespace string) InferenceGraphNamespaceLister { - return inferenceGraphNamespaceLister{indexer: s.indexer, namespace: namespace} + return inferenceGraphNamespaceLister{listers.NewNamespaced[*v1alpha1.InferenceGraph](s.ResourceIndexer, namespace)} } // InferenceGraphNamespaceLister helps list and get InferenceGraphs. @@ -74,26 +66,5 @@ type InferenceGraphNamespaceLister interface { // inferenceGraphNamespaceLister implements the InferenceGraphNamespaceLister // interface. type inferenceGraphNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all InferenceGraphs in the indexer for a given namespace. -func (s inferenceGraphNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.InferenceGraph, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.InferenceGraph)) - }) - return ret, err -} - -// Get retrieves the InferenceGraph from the indexer for a given namespace and name. -func (s inferenceGraphNamespaceLister) Get(name string) (*v1alpha1.InferenceGraph, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("inferencegraph"), name) - } - return obj.(*v1alpha1.InferenceGraph), nil + listers.ResourceIndexer[*v1alpha1.InferenceGraph] } diff --git a/pkg/client/listers/serving/v1alpha1/localmodelcache.go b/pkg/client/listers/serving/v1alpha1/localmodelcache.go index e3cd5f5f889..06af24b07da 100644 --- a/pkg/client/listers/serving/v1alpha1/localmodelcache.go +++ b/pkg/client/listers/serving/v1alpha1/localmodelcache.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type LocalModelCacheLister interface { // localModelCacheLister implements the LocalModelCacheLister interface. type localModelCacheLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.LocalModelCache] } // NewLocalModelCacheLister returns a new LocalModelCacheLister. func NewLocalModelCacheLister(indexer cache.Indexer) LocalModelCacheLister { - return &localModelCacheLister{indexer: indexer} -} - -// List lists all LocalModelCaches in the indexer. -func (s *localModelCacheLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelCache, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelCache)) - }) - return ret, err + return &localModelCacheLister{listers.New[*v1alpha1.LocalModelCache](indexer, v1alpha1.Resource("localmodelcache"))} } // LocalModelCaches returns an object that can list and get LocalModelCaches. func (s *localModelCacheLister) LocalModelCaches(namespace string) LocalModelCacheNamespaceLister { - return localModelCacheNamespaceLister{indexer: s.indexer, namespace: namespace} + return localModelCacheNamespaceLister{listers.NewNamespaced[*v1alpha1.LocalModelCache](s.ResourceIndexer, namespace)} } // LocalModelCacheNamespaceLister helps list and get LocalModelCaches. @@ -74,26 +66,5 @@ type LocalModelCacheNamespaceLister interface { // localModelCacheNamespaceLister implements the LocalModelCacheNamespaceLister // interface. type localModelCacheNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all LocalModelCaches in the indexer for a given namespace. -func (s localModelCacheNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelCache, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelCache)) - }) - return ret, err -} - -// Get retrieves the LocalModelCache from the indexer for a given namespace and name. -func (s localModelCacheNamespaceLister) Get(name string) (*v1alpha1.LocalModelCache, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("localmodelcache"), name) - } - return obj.(*v1alpha1.LocalModelCache), nil + listers.ResourceIndexer[*v1alpha1.LocalModelCache] } diff --git a/pkg/client/listers/serving/v1alpha1/localmodelnode.go b/pkg/client/listers/serving/v1alpha1/localmodelnode.go index ace902f1489..13b165e702c 100644 --- a/pkg/client/listers/serving/v1alpha1/localmodelnode.go +++ b/pkg/client/listers/serving/v1alpha1/localmodelnode.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type LocalModelNodeLister interface { // localModelNodeLister implements the LocalModelNodeLister interface. type localModelNodeLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.LocalModelNode] } // NewLocalModelNodeLister returns a new LocalModelNodeLister. func NewLocalModelNodeLister(indexer cache.Indexer) LocalModelNodeLister { - return &localModelNodeLister{indexer: indexer} -} - -// List lists all LocalModelNodes in the indexer. -func (s *localModelNodeLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelNode, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelNode)) - }) - return ret, err + return &localModelNodeLister{listers.New[*v1alpha1.LocalModelNode](indexer, v1alpha1.Resource("localmodelnode"))} } // LocalModelNodes returns an object that can list and get LocalModelNodes. func (s *localModelNodeLister) LocalModelNodes(namespace string) LocalModelNodeNamespaceLister { - return localModelNodeNamespaceLister{indexer: s.indexer, namespace: namespace} + return localModelNodeNamespaceLister{listers.NewNamespaced[*v1alpha1.LocalModelNode](s.ResourceIndexer, namespace)} } // LocalModelNodeNamespaceLister helps list and get LocalModelNodes. @@ -74,26 +66,5 @@ type LocalModelNodeNamespaceLister interface { // localModelNodeNamespaceLister implements the LocalModelNodeNamespaceLister // interface. type localModelNodeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all LocalModelNodes in the indexer for a given namespace. -func (s localModelNodeNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelNode, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelNode)) - }) - return ret, err -} - -// Get retrieves the LocalModelNode from the indexer for a given namespace and name. -func (s localModelNodeNamespaceLister) Get(name string) (*v1alpha1.LocalModelNode, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("localmodelnode"), name) - } - return obj.(*v1alpha1.LocalModelNode), nil + listers.ResourceIndexer[*v1alpha1.LocalModelNode] } diff --git a/pkg/client/listers/serving/v1alpha1/localmodelnodegroup.go b/pkg/client/listers/serving/v1alpha1/localmodelnodegroup.go index 60dc28640b4..0b27018fd4f 100644 --- a/pkg/client/listers/serving/v1alpha1/localmodelnodegroup.go +++ b/pkg/client/listers/serving/v1alpha1/localmodelnodegroup.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type LocalModelNodeGroupLister interface { // localModelNodeGroupLister implements the LocalModelNodeGroupLister interface. type localModelNodeGroupLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.LocalModelNodeGroup] } // NewLocalModelNodeGroupLister returns a new LocalModelNodeGroupLister. func NewLocalModelNodeGroupLister(indexer cache.Indexer) LocalModelNodeGroupLister { - return &localModelNodeGroupLister{indexer: indexer} -} - -// List lists all LocalModelNodeGroups in the indexer. -func (s *localModelNodeGroupLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelNodeGroup, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelNodeGroup)) - }) - return ret, err + return &localModelNodeGroupLister{listers.New[*v1alpha1.LocalModelNodeGroup](indexer, v1alpha1.Resource("localmodelnodegroup"))} } // LocalModelNodeGroups returns an object that can list and get LocalModelNodeGroups. func (s *localModelNodeGroupLister) LocalModelNodeGroups(namespace string) LocalModelNodeGroupNamespaceLister { - return localModelNodeGroupNamespaceLister{indexer: s.indexer, namespace: namespace} + return localModelNodeGroupNamespaceLister{listers.NewNamespaced[*v1alpha1.LocalModelNodeGroup](s.ResourceIndexer, namespace)} } // LocalModelNodeGroupNamespaceLister helps list and get LocalModelNodeGroups. @@ -74,26 +66,5 @@ type LocalModelNodeGroupNamespaceLister interface { // localModelNodeGroupNamespaceLister implements the LocalModelNodeGroupNamespaceLister // interface. type localModelNodeGroupNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all LocalModelNodeGroups in the indexer for a given namespace. -func (s localModelNodeGroupNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.LocalModelNodeGroup, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalModelNodeGroup)) - }) - return ret, err -} - -// Get retrieves the LocalModelNodeGroup from the indexer for a given namespace and name. -func (s localModelNodeGroupNamespaceLister) Get(name string) (*v1alpha1.LocalModelNodeGroup, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("localmodelnodegroup"), name) - } - return obj.(*v1alpha1.LocalModelNodeGroup), nil + listers.ResourceIndexer[*v1alpha1.LocalModelNodeGroup] } diff --git a/pkg/client/listers/serving/v1alpha1/servingruntime.go b/pkg/client/listers/serving/v1alpha1/servingruntime.go index f94d3fc32ca..adcee2fd395 100644 --- a/pkg/client/listers/serving/v1alpha1/servingruntime.go +++ b/pkg/client/listers/serving/v1alpha1/servingruntime.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type ServingRuntimeLister interface { // servingRuntimeLister implements the ServingRuntimeLister interface. type servingRuntimeLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.ServingRuntime] } // NewServingRuntimeLister returns a new ServingRuntimeLister. func NewServingRuntimeLister(indexer cache.Indexer) ServingRuntimeLister { - return &servingRuntimeLister{indexer: indexer} -} - -// List lists all ServingRuntimes in the indexer. -func (s *servingRuntimeLister) List(selector labels.Selector) (ret []*v1alpha1.ServingRuntime, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ServingRuntime)) - }) - return ret, err + return &servingRuntimeLister{listers.New[*v1alpha1.ServingRuntime](indexer, v1alpha1.Resource("servingruntime"))} } // ServingRuntimes returns an object that can list and get ServingRuntimes. func (s *servingRuntimeLister) ServingRuntimes(namespace string) ServingRuntimeNamespaceLister { - return servingRuntimeNamespaceLister{indexer: s.indexer, namespace: namespace} + return servingRuntimeNamespaceLister{listers.NewNamespaced[*v1alpha1.ServingRuntime](s.ResourceIndexer, namespace)} } // ServingRuntimeNamespaceLister helps list and get ServingRuntimes. @@ -74,26 +66,5 @@ type ServingRuntimeNamespaceLister interface { // servingRuntimeNamespaceLister implements the ServingRuntimeNamespaceLister // interface. type servingRuntimeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all ServingRuntimes in the indexer for a given namespace. -func (s servingRuntimeNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ServingRuntime, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ServingRuntime)) - }) - return ret, err -} - -// Get retrieves the ServingRuntime from the indexer for a given namespace and name. -func (s servingRuntimeNamespaceLister) Get(name string) (*v1alpha1.ServingRuntime, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("servingruntime"), name) - } - return obj.(*v1alpha1.ServingRuntime), nil + listers.ResourceIndexer[*v1alpha1.ServingRuntime] } diff --git a/pkg/client/listers/serving/v1alpha1/trainedmodel.go b/pkg/client/listers/serving/v1alpha1/trainedmodel.go index 2d17690e939..2d0d4c6754d 100644 --- a/pkg/client/listers/serving/v1alpha1/trainedmodel.go +++ b/pkg/client/listers/serving/v1alpha1/trainedmodel.go @@ -20,8 +20,8 @@ package v1alpha1 import ( v1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type TrainedModelLister interface { // trainedModelLister implements the TrainedModelLister interface. type trainedModelLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.TrainedModel] } // NewTrainedModelLister returns a new TrainedModelLister. func NewTrainedModelLister(indexer cache.Indexer) TrainedModelLister { - return &trainedModelLister{indexer: indexer} -} - -// List lists all TrainedModels in the indexer. -func (s *trainedModelLister) List(selector labels.Selector) (ret []*v1alpha1.TrainedModel, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.TrainedModel)) - }) - return ret, err + return &trainedModelLister{listers.New[*v1alpha1.TrainedModel](indexer, v1alpha1.Resource("trainedmodel"))} } // TrainedModels returns an object that can list and get TrainedModels. func (s *trainedModelLister) TrainedModels(namespace string) TrainedModelNamespaceLister { - return trainedModelNamespaceLister{indexer: s.indexer, namespace: namespace} + return trainedModelNamespaceLister{listers.NewNamespaced[*v1alpha1.TrainedModel](s.ResourceIndexer, namespace)} } // TrainedModelNamespaceLister helps list and get TrainedModels. @@ -74,26 +66,5 @@ type TrainedModelNamespaceLister interface { // trainedModelNamespaceLister implements the TrainedModelNamespaceLister // interface. type trainedModelNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TrainedModels in the indexer for a given namespace. -func (s trainedModelNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.TrainedModel, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.TrainedModel)) - }) - return ret, err -} - -// Get retrieves the TrainedModel from the indexer for a given namespace and name. -func (s trainedModelNamespaceLister) Get(name string) (*v1alpha1.TrainedModel, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("trainedmodel"), name) - } - return obj.(*v1alpha1.TrainedModel), nil + listers.ResourceIndexer[*v1alpha1.TrainedModel] } diff --git a/pkg/client/listers/serving/v1beta1/inferenceservice.go b/pkg/client/listers/serving/v1beta1/inferenceservice.go index e11cfee019b..1fa282006c5 100644 --- a/pkg/client/listers/serving/v1beta1/inferenceservice.go +++ b/pkg/client/listers/serving/v1beta1/inferenceservice.go @@ -20,8 +20,8 @@ package v1beta1 import ( v1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" ) @@ -38,25 +38,17 @@ type InferenceServiceLister interface { // inferenceServiceLister implements the InferenceServiceLister interface. type inferenceServiceLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.InferenceService] } // NewInferenceServiceLister returns a new InferenceServiceLister. func NewInferenceServiceLister(indexer cache.Indexer) InferenceServiceLister { - return &inferenceServiceLister{indexer: indexer} -} - -// List lists all InferenceServices in the indexer. -func (s *inferenceServiceLister) List(selector labels.Selector) (ret []*v1beta1.InferenceService, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.InferenceService)) - }) - return ret, err + return &inferenceServiceLister{listers.New[*v1beta1.InferenceService](indexer, v1beta1.Resource("inferenceservice"))} } // InferenceServices returns an object that can list and get InferenceServices. func (s *inferenceServiceLister) InferenceServices(namespace string) InferenceServiceNamespaceLister { - return inferenceServiceNamespaceLister{indexer: s.indexer, namespace: namespace} + return inferenceServiceNamespaceLister{listers.NewNamespaced[*v1beta1.InferenceService](s.ResourceIndexer, namespace)} } // InferenceServiceNamespaceLister helps list and get InferenceServices. @@ -74,26 +66,5 @@ type InferenceServiceNamespaceLister interface { // inferenceServiceNamespaceLister implements the InferenceServiceNamespaceLister // interface. type inferenceServiceNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all InferenceServices in the indexer for a given namespace. -func (s inferenceServiceNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.InferenceService, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.InferenceService)) - }) - return ret, err -} - -// Get retrieves the InferenceService from the indexer for a given namespace and name. -func (s inferenceServiceNamespaceLister) Get(name string) (*v1beta1.InferenceService, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("inferenceservice"), name) - } - return obj.(*v1beta1.InferenceService), nil + listers.ResourceIndexer[*v1beta1.InferenceService] } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 89b2d25e224..3e2bef511bc 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -22,11 +22,11 @@ import ( "regexp" "strings" - "knative.dev/serving/pkg/apis/autoscaling" - - "knative.dev/pkg/network" - + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "knative.dev/pkg/network" + "knative.dev/serving/pkg/apis/autoscaling" ) // KServe Constants @@ -53,6 +53,8 @@ var ( const ( RouterHeadersPropagateEnvVar = "PROPAGATE_HEADERS" InferenceGraphLabel = "serving.kserve.io/inferencegraph" + RouterReadinessEndpoint = "/readyz" + RouterPort = 8080 ) // TrainedModel Constants @@ -495,6 +497,9 @@ const ( const ( IstioVirtualServiceKind = "VirtualService" KnativeServiceKind = "Service" + HTTPRouteKind = "HTTPRoute" + GatewayKind = "Gateway" + ServiceKind = "Service" ) // Model Parallel Options @@ -642,6 +647,11 @@ func ExplainPrefix() string { return "^/v1/models/[\\w-]+:explain$" } +// FallbackPrefix returns the regex pattern to match any path +func FallbackPrefix() string { + return "^/.*$" +} + func PathBasedExplainPrefix() string { return "(/v1/models/[\\w-]+:explain)$" } @@ -720,3 +730,24 @@ func GetProtocolVersionString(protocol ProtocolVersion) InferenceServiceProtocol return ProtocolUnknown } } + +func GetRouterReadinessProbe() *corev1.Probe { + probe := &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: RouterReadinessEndpoint, + Port: intstr.IntOrString{ + Type: intstr.Int, + IntVal: RouterPort, + }, + Scheme: corev1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 2, + PeriodSeconds: 5, + SuccessThreshold: 1, + FailureThreshold: 3, + } + return probe +} diff --git a/pkg/controller/v1alpha1/inferencegraph/controller_test.go b/pkg/controller/v1alpha1/inferencegraph/controller_test.go index a2634dda740..f3cd0042558 100644 --- a/pkg/controller/v1alpha1/inferencegraph/controller_test.go +++ b/pkg/controller/v1alpha1/inferencegraph/controller_test.go @@ -21,9 +21,6 @@ import ( "fmt" "time" - "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "github.com/kserve/kserve/pkg/constants" - "github.com/kserve/kserve/pkg/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "google.golang.org/protobuf/proto" @@ -36,6 +33,10 @@ import ( knservingv1 "knative.dev/serving/pkg/apis/serving/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" + "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" ) var _ = Describe("Inference Graph controller test", func() { @@ -65,6 +66,8 @@ var _ = Describe("Inference Graph controller test", func() { } ) + var expectedReadinessProbe = constants.GetRouterReadinessProbe() + Context("When creating an inferencegraph with headers in global config", func() { It("Should create a knative service with headers as env var of podspec", func() { By("By creating a new InferenceGraph") @@ -170,6 +173,7 @@ var _ = Describe("Inference Graph controller test", func() { v1.ResourceMemory: resource.MustParse("100Mi"), }, }, + ReadinessProbe: expectedReadinessProbe, SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), @@ -328,6 +332,7 @@ var _ = Describe("Inference Graph controller test", func() { v1.ResourceMemory: resource.MustParse("123Mi"), }, }, + ReadinessProbe: expectedReadinessProbe, SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), @@ -509,6 +514,7 @@ var _ = Describe("Inference Graph controller test", func() { Drop: []v1.Capability{v1.Capability("ALL")}, }, }, + ReadinessProbe: expectedReadinessProbe, VolumeMounts: []v1.VolumeMount{ { Name: "openshift-service-ca-bundle", diff --git a/pkg/controller/v1alpha1/inferencegraph/knative_reconciler.go b/pkg/controller/v1alpha1/inferencegraph/knative_reconciler.go index 2caf8dac1a4..da252b58efd 100644 --- a/pkg/controller/v1alpha1/inferencegraph/knative_reconciler.go +++ b/pkg/controller/v1alpha1/inferencegraph/knative_reconciler.go @@ -203,6 +203,7 @@ func createKnativeService(componentMeta metav1.ObjectMeta, graph *v1alpha1api.In Drop: []v1.Capability{v1.Capability("ALL")}, }, }, + ReadinessProbe: constants.GetRouterReadinessProbe(), VolumeMounts: []v1.VolumeMount{ { Name: "openshift-service-ca-bundle", diff --git a/pkg/controller/v1alpha1/inferencegraph/raw_ig.go b/pkg/controller/v1alpha1/inferencegraph/raw_ig.go index 49321f0e536..67e9b510055 100644 --- a/pkg/controller/v1alpha1/inferencegraph/raw_ig.go +++ b/pkg/controller/v1alpha1/inferencegraph/raw_ig.go @@ -63,7 +63,8 @@ func createInferenceGraphPodSpec(graph *v1alpha1api.InferenceGraph, config *Rout "--graph-json", string(bytes), }, - Resources: constructResourceRequirements(*graph, *config), + Resources: constructResourceRequirements(*graph, *config), + ReadinessProbe: constants.GetRouterReadinessProbe(), SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), diff --git a/pkg/controller/v1alpha1/inferencegraph/raw_ig_test.go b/pkg/controller/v1alpha1/inferencegraph/raw_ig_test.go index 0a26c740b86..f2537b9dc71 100644 --- a/pkg/controller/v1alpha1/inferencegraph/raw_ig_test.go +++ b/pkg/controller/v1alpha1/inferencegraph/raw_ig_test.go @@ -60,6 +60,8 @@ func TestCreateInferenceGraphPodSpec(t *testing.T) { }, } + expectedReadinessProbe := constants.GetRouterReadinessProbe() + testIGSpecs := map[string]*InferenceGraph{ "basic": { ObjectMeta: metav1.ObjectMeta{ @@ -162,6 +164,7 @@ func TestCreateInferenceGraphPodSpec(t *testing.T) { v1.ResourceMemory: resource.MustParse("100Mi"), }, }, + ReadinessProbe: expectedReadinessProbe, SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), @@ -200,6 +203,7 @@ func TestCreateInferenceGraphPodSpec(t *testing.T) { v1.ResourceMemory: resource.MustParse("100Mi"), }, }, + ReadinessProbe: expectedReadinessProbe, SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), @@ -232,6 +236,7 @@ func TestCreateInferenceGraphPodSpec(t *testing.T) { v1.ResourceMemory: resource.MustParse("100Mi"), }, }, + ReadinessProbe: expectedReadinessProbe, SecurityContext: &v1.SecurityContext{ Privileged: proto.Bool(false), RunAsNonRoot: proto.Bool(true), diff --git a/pkg/controller/v1alpha1/localmodel/controller.go b/pkg/controller/v1alpha1/localmodel/controller.go index a55feee6dcd..3aea5e46f59 100644 --- a/pkg/controller/v1alpha1/localmodel/controller.go +++ b/pkg/controller/v1alpha1/localmodel/controller.go @@ -175,7 +175,11 @@ func (c *LocalModelReconciler) ReconcileForIsvcs(ctx context.Context, localModel c.Log.Error(err, "cannot update status", "name", localModel.Name) } - // Remove PVs and PVCs if the namespace does not have isvcs + /* + Remove PVs and PVCs if the namespace does not have isvcs + It only deletes the pvc and pvs with ownerReference as the localModel + And the pv must be of the format pvc.Name+"-"+pvc.Namespace + */ pvcs := v1.PersistentVolumeClaimList{} if err := c.List(ctx, &pvcs, client.MatchingFields{ownerKey: localModel.Name}); err != nil { c.Log.Error(err, "unable to list PVCs", "name", localModel.Name) @@ -228,6 +232,7 @@ func (c *LocalModelReconciler) ReconcileForIsvcs(ctx context.Context, localModel return nil } +// Reconcile // Step 1 - Checks if the CR is in the deletion process. Deletion completes when all LocalModelNodes have been updated // Step 2 - Adds this model to LocalModelNode resources in the node group // Step 3 - Creates PV & PVC for model download @@ -295,6 +300,10 @@ func (c *LocalModelReconciler) Reconcile(ctx context.Context, req ctrl.Request) c.Log.Error(err, "Create PVC err", "name", pv.Name) } + if localModelConfig.DisableVolumeManagement { + return ctrl.Result{}, nil + } + // Step 4 - Creates PV & PVCs for namespaces with isvcs using this model err = c.ReconcileForIsvcs(ctx, localModel, nodeGroup, localModelConfig.JobNamespace) return ctrl.Result{}, err @@ -371,6 +380,12 @@ func (c *LocalModelReconciler) localmodelNodeFunc(ctx context.Context, obj clien } func (c *LocalModelReconciler) SetupWithManager(mgr ctrl.Manager) error { + localModelConfig, err := v1beta1.NewLocalModelConfig(c.Clientset) + if err != nil { + c.Log.Error(err, "Failed to get local model config during controller manager setup") + return err + } + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &v1.PersistentVolumeClaim{}, ownerKey, func(rawObj client.Object) []string { pvc := rawObj.(*v1.PersistentVolumeClaim) owner := metav1.GetControllerOf(pvc) @@ -452,14 +467,17 @@ func (c *LocalModelReconciler) SetupWithManager(mgr ctrl.Manager) error { }, } - return ctrl.NewControllerManagedBy(mgr). + controllerBuilder := ctrl.NewControllerManagedBy(mgr). For(&v1alpha1api.LocalModelCache{}). // Ownes PersistentVolumes and PersistentVolumeClaims that is created by this local model controller Owns(&v1.PersistentVolume{}). - Owns(&v1.PersistentVolumeClaim{}). - // Creates or deletes pv/pvcs when isvcs got created or deleted - Watches(&v1beta1.InferenceService{}, handler.EnqueueRequestsFromMapFunc(c.isvcFunc), builder.WithPredicates(isvcPredicates)). - // Downloads models to new nodes + Owns(&v1.PersistentVolumeClaim{}) + + if !localModelConfig.DisableVolumeManagement { + controllerBuilder.Watches(&v1beta1.InferenceService{}, handler.EnqueueRequestsFromMapFunc(c.isvcFunc), builder.WithPredicates(isvcPredicates)) + } + + return controllerBuilder. Watches(&v1.Node{}, handler.EnqueueRequestsFromMapFunc(c.nodeFunc), builder.WithPredicates(nodePredicates)). // Updates model status when localmodelnode status changes Watches(&v1alpha1.LocalModelNode{}, handler.EnqueueRequestsFromMapFunc(c.localmodelNodeFunc), builder.WithPredicates(localModelNodePredicates)). diff --git a/pkg/controller/v1alpha1/localmodel/controller_test.go b/pkg/controller/v1alpha1/localmodel/controller_test.go index a798fe457ff..a8ac3dfc116 100644 --- a/pkg/controller/v1alpha1/localmodel/controller_test.go +++ b/pkg/controller/v1alpha1/localmodel/controller_test.go @@ -23,13 +23,20 @@ import ( "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" "github.com/kserve/kserve/pkg/apis/serving/v1beta1" "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + crconfig "sigs.k8s.io/controller-runtime/pkg/config" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" ) var _ = Describe("CachedModel controller", func() { @@ -100,35 +107,29 @@ var _ = Describe("CachedModel controller", func() { }`, } ) + Context("When creating a local model", func() { - It("Should create pv, pvc, localmodelnode, and update status from localmodelnode", func() { - var configMap = &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.InferenceServiceConfigMapName, - Namespace: constants.KServeNamespace, - }, - Data: configs, - } - Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) - defer k8sClient.Delete(context.TODO(), configMap) + var ( + configMap *v1.ConfigMap + clusterStorageContainer *v1alpha1.ClusterStorageContainer + nodeGroup *v1alpha1.LocalModelNodeGroup + ) + BeforeEach(func() { + configMap, clusterStorageContainer, nodeGroup = genericSetup(configs, clusterStorageContainerSpec, localModelNodeGroupSpec) + initializeManager(ctx, cfg) + }) - clusterStorageContainer := &v1alpha1.ClusterStorageContainer{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: clusterStorageContainerSpec, - } - Expect(k8sClient.Create(ctx, clusterStorageContainer)).Should(Succeed()) + AfterEach(func() { + defer k8sClient.Delete(ctx, configMap) defer k8sClient.Delete(ctx, clusterStorageContainer) - - nodeGroup := &v1alpha1.LocalModelNodeGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gpu", - }, - Spec: localModelNodeGroupSpec, - } - Expect(k8sClient.Create(ctx, nodeGroup)).Should(Succeed()) defer k8sClient.Delete(ctx, nodeGroup) + }) + + It("Should create pv, pvc, localmodelnode, and update status from localmodelnode", func() { + defer GinkgoRecover() + configMap := &v1.ConfigMap{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace}, configMap) + Expect(err).ToNot(HaveOccurred(), "InferenceService ConfigMap should exist") cachedModel := &v1alpha1.LocalModelCache{ ObjectMeta: metav1.ObjectMeta{ @@ -219,34 +220,7 @@ var _ = Describe("CachedModel controller", func() { }) It("Should create pvs and pvcs for inference services", func() { - var configMap = &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.InferenceServiceConfigMapName, - Namespace: constants.KServeNamespace, - }, - Data: configs, - } - Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) - defer k8sClient.Delete(context.TODO(), configMap) - - clusterStorageContainer := &v1alpha1.ClusterStorageContainer{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: clusterStorageContainerSpec, - } - Expect(k8sClient.Create(ctx, clusterStorageContainer)).Should(Succeed()) - defer k8sClient.Delete(ctx, clusterStorageContainer) - - nodeGroup := &v1alpha1.LocalModelNodeGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gpu", - }, - Spec: localModelNodeGroupSpec, - } - Expect(k8sClient.Create(ctx, nodeGroup)).Should(Succeed()) - defer k8sClient.Delete(ctx, nodeGroup) - + defer GinkgoRecover() modelName := "iris2" isvcNamespace := "default" isvcName := "foo" @@ -350,36 +324,102 @@ var _ = Describe("CachedModel controller", func() { }, timeout, interval).Should(BeTrue()) }) }) - Context("When creating multiple localModels", func() { - // With two nodes and two local models, each node should have both local models - It("Should create localModelNode correctly", func() { - var configMap = &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.InferenceServiceConfigMapName, - Namespace: constants.KServeNamespace, - }, - Data: configs, - } - Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) - defer k8sClient.Delete(context.TODO(), configMap) - clusterStorageContainer := &v1alpha1.ClusterStorageContainer{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: clusterStorageContainerSpec, + Context("When DisableVolumeManagement is set to true", func() { + var ( + configMap *v1.ConfigMap + clusterStorageContainer *v1alpha1.ClusterStorageContainer + nodeGroup *v1alpha1.LocalModelNodeGroup + ) + BeforeEach(func() { + configs = map[string]string{ + "localModel": `{ + "jobNamespace": "kserve-localmodel-jobs", + "defaultJobImage": "kserve/storage-initializer:latest", + "disableVolumeManagement": true + }`, } - Expect(k8sClient.Create(ctx, clusterStorageContainer)).Should(Succeed()) + configMap, clusterStorageContainer, nodeGroup = genericSetup(configs, clusterStorageContainerSpec, localModelNodeGroupSpec) + initializeManager(ctx, cfg) + }) + + AfterEach(func() { + defer k8sClient.Delete(ctx, configMap) defer k8sClient.Delete(ctx, clusterStorageContainer) + defer k8sClient.Delete(ctx, nodeGroup) + }) - nodeGroup := &v1alpha1.LocalModelNodeGroup{ + It("Should NOT create/delete pvs and pvcs if localmodel config value DisableVolumeManagement is true", func() { + defer GinkgoRecover() + testNamespace := "test-namespace" + namespaceObj := createTestNamespace(ctx, testNamespace) + defer k8sClient.Delete(ctx, namespaceObj) + + modelName := "iris3" + cachedModel := &v1alpha1.LocalModelCache{ ObjectMeta: metav1.ObjectMeta{ - Name: "gpu", + Name: modelName, }, - Spec: localModelNodeGroupSpec, + Spec: localModelSpec, + } + Expect(k8sClient.Create(ctx, cachedModel)).Should(Succeed()) + defer k8sClient.Delete(ctx, cachedModel) + + pvcName := "test-pvc" + pvName := pvcName + "-" + testNamespace + + pv := createTestPV(ctx, pvName, testNamespace, cachedModel) + defer k8sClient.Delete(ctx, pv) + + pvc := createTestPVC(ctx, pvcName, testNamespace, pvName, cachedModel) + defer k8sClient.Delete(ctx, pvc) + + // Expects test-pv and test-pvc to not get deleted + pvLookupKey := types.NamespacedName{Name: pvName} + pvcLookupKey := types.NamespacedName{Name: pvcName, Namespace: testNamespace} + + persistentVolume := &v1.PersistentVolume{} + Eventually(func() bool { + err := k8sClient.Get(ctx, pvLookupKey, persistentVolume) + return err == nil && persistentVolume != nil + }, timeout, interval).Should(BeTrue()) + + persistentVolumeClaim := &v1.PersistentVolumeClaim{} + Eventually(func() bool { + err := k8sClient.Get(ctx, pvcLookupKey, persistentVolumeClaim) + return err == nil && persistentVolumeClaim != nil + }, timeout, interval).Should(BeTrue()) + }) + }) + + Context("When creating multiple localModels", func() { + var ( + configMap *v1.ConfigMap + clusterStorageContainer *v1alpha1.ClusterStorageContainer + nodeGroup *v1alpha1.LocalModelNodeGroup + + configs = map[string]string{ + "localModel": `{ + "jobNamespace": "kserve-localmodel-jobs", + "defaultJobImage": "kserve/storage-initializer:latest" + }`, } - Expect(k8sClient.Create(ctx, nodeGroup)).Should(Succeed()) + ) + BeforeEach(func() { + configMap, clusterStorageContainer, nodeGroup = genericSetup(configs, clusterStorageContainerSpec, localModelNodeGroupSpec) + + initializeManager(ctx, cfg) + }) + + AfterEach(func() { + defer k8sClient.Delete(ctx, configMap) + defer k8sClient.Delete(ctx, clusterStorageContainer) defer k8sClient.Delete(ctx, nodeGroup) + }) + + // With two nodes and two local models, each node should have both local models + It("Should create localModelNode correctly", func() { + defer GinkgoRecover() node1 := &v1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -467,3 +507,135 @@ var _ = Describe("CachedModel controller", func() { }) }) }) + +func ptrToBool(b bool) *bool { + return &b +} + +func createTestNamespace(ctx context.Context, name string) *v1.Namespace { + namespace := &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } + Expect(k8sClient.Create(ctx, namespace)).Should(Succeed()) + return namespace +} + +func createTestPV(ctx context.Context, pvName, namespace string, cachedModel *v1alpha1.LocalModelCache) *v1.PersistentVolume { + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvName, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "serving.kserve.io/v1alpha1", + Kind: "LocalModelCache", + Name: cachedModel.Name, + UID: cachedModel.UID, + Controller: ptrToBool(true), + }, + }, + }, + Spec: v1.PersistentVolumeSpec{ + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + Capacity: v1.ResourceList{ + v1.ResourceStorage: resource.MustParse("2Gi"), + }, + PersistentVolumeSource: v1.PersistentVolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/mnt/data", + Type: ptr.To(v1.HostPathDirectoryOrCreate), + }, + }, + }, + } + Expect(k8sClient.Create(ctx, pv)).Should(Succeed()) + return pv +} + +func createTestPVC(ctx context.Context, pvcName, namespace, pvName string, cachedModel *v1alpha1.LocalModelCache) *v1.PersistentVolumeClaim { + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "serving.kserve.io/v1alpha1", + Kind: "LocalModelCache", + Name: cachedModel.Name, + UID: cachedModel.UID, + Controller: ptrToBool(true), + }, + }, + }, + Spec: v1.PersistentVolumeClaimSpec{ + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + Resources: v1.VolumeResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceStorage: resource.MustParse("2Gi"), + }, + }, + VolumeName: pvName, + }, + } + Expect(k8sClient.Create(ctx, pvc)).Should(Succeed()) + return pvc +} + +func genericSetup(configs map[string]string, clusterStorageContainerSpec v1alpha1.StorageContainerSpec, localModelNodeGroupSpec v1alpha1.LocalModelNodeGroupSpec) (*v1.ConfigMap, *v1alpha1.ClusterStorageContainer, *v1alpha1.LocalModelNodeGroup) { + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + + clusterStorageContainer := &v1alpha1.ClusterStorageContainer{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: clusterStorageContainerSpec, + } + Expect(k8sClient.Create(ctx, clusterStorageContainer)).Should(Succeed()) + + nodeGroup := &v1alpha1.LocalModelNodeGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gpu", + }, + Spec: localModelNodeGroupSpec, + } + Expect(k8sClient.Create(ctx, nodeGroup)).Should(Succeed()) + + return configMap, clusterStorageContainer, nodeGroup +} + +func initializeManager(ctx context.Context, cfg *rest.Config) { + clientset, err := kubernetes.NewForConfig(cfg) + Expect(err).ToNot(HaveOccurred()) + Expect(clientset).ToNot(BeNil()) + k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", + }, + Controller: crconfig.Controller{ + SkipNameValidation: utils.ToPointer(true), + }, + }) + Expect(err).ToNot(HaveOccurred()) + err = (&LocalModelReconciler{ + Client: k8sManager.GetClient(), + Clientset: clientset, + Scheme: scheme.Scheme, + Log: ctrl.Log.WithName("v1alpha1LocalModelController"), + }).SetupWithManager(k8sManager) + + Expect(err).ToNot(HaveOccurred()) + + go func() { + err = k8sManager.Start(ctx) + Expect(err).ToNot(HaveOccurred()) + }() +} diff --git a/pkg/controller/v1alpha1/localmodel/suite_test.go b/pkg/controller/v1alpha1/localmodel/suite_test.go index 530f119700c..4168b741add 100644 --- a/pkg/controller/v1alpha1/localmodel/suite_test.go +++ b/pkg/controller/v1alpha1/localmodel/suite_test.go @@ -25,16 +25,13 @@ import ( . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" knservingv1 "knative.dev/serving/pkg/apis/serving/v1" - ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" kservev1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1" @@ -85,10 +82,6 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) Expect(k8sClient).ToNot(BeNil()) - clientset, err := kubernetes.NewForConfig(cfg) - Expect(err).ToNot(HaveOccurred()) - Expect(clientset).ToNot(BeNil()) - // Creates namespace kserveNamespaceObj := &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -102,27 +95,6 @@ var _ = BeforeSuite(func() { } Expect(k8sClient.Create(context.Background(), kserveNamespaceObj)).Should(Succeed()) Expect(k8sClient.Create(context.Background(), jobsNamespaceObj)).Should(Succeed()) - - k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme.Scheme, - Metrics: metricsserver.Options{ - BindAddress: "0", - }, - }) - - Expect(err).ToNot(HaveOccurred()) - err = (&LocalModelReconciler{ - Client: k8sManager.GetClient(), - Clientset: clientset, - Scheme: scheme.Scheme, - Log: ctrl.Log.WithName("v1alpha1LocalModelController"), - }).SetupWithManager(k8sManager) - Expect(err).ToNot(HaveOccurred()) - defer GinkgoRecover() - go func() { - err = k8sManager.Start(ctx) - Expect(err).ToNot(HaveOccurred()) - }() }) var _ = AfterSuite(func() { diff --git a/pkg/controller/v1alpha1/localmodelnode/controller.go b/pkg/controller/v1alpha1/localmodelnode/controller.go index 620dfbc41af..c87a250cea9 100644 --- a/pkg/controller/v1alpha1/localmodelnode/controller.go +++ b/pkg/controller/v1alpha1/localmodelnode/controller.go @@ -123,13 +123,14 @@ func (c *LocalModelNodeReconciler) launchJob(ctx context.Context, localModelNode return nil, err } jobs := c.Clientset.BatchV1().Jobs(jobNamespace) - job, err = jobs.Create(ctx, job, metav1.CreateOptions{}) - c.Log.Info("Creating job", "name", job.Name, "namespace", job.Namespace) + createdJob, err := jobs.Create(ctx, job, metav1.CreateOptions{}) if err != nil { c.Log.Error(err, "Failed to create job.", "name", job.Name) return nil, err } - return job, err + c.Log.Info("Created job", "name", createdJob.Name, "namespace", createdJob.Namespace, + "model", modelInfo.ModelName) + return createdJob, err } // Fetches container spec for model download container, use the default KServe image if not found @@ -163,7 +164,7 @@ func (c *LocalModelNodeReconciler) getContainerSpecForStorageUri(ctx context.Con return defaultContainer, nil } -func (c *LocalModelNodeReconciler) getLatestJob(ctx context.Context, modelName string, nodeName string, excludeSucceeded bool) (*batchv1.Job, error) { +func (c *LocalModelNodeReconciler) getLatestJob(ctx context.Context, modelName string, nodeName string) (*batchv1.Job, int, error) { jobList := &batchv1.JobList{} labelSelector := map[string]string{ "model": modelName, @@ -172,21 +173,18 @@ func (c *LocalModelNodeReconciler) getLatestJob(ctx context.Context, modelName s if err := c.Client.List(ctx, jobList, client.InNamespace(jobNamespace), client.MatchingLabels(labelSelector)); err != nil { if errors.IsNotFound(err) { c.Log.Info("Job not found", "model", modelName) - return nil, nil + return nil, 0, nil } - return nil, err + return nil, 0, err } c.Log.Info("Found jobs", "model", modelName, "num of jobs", len(jobList.Items)) var latestJob *batchv1.Job for i, job := range jobList.Items { - if excludeSucceeded && job.Status.Succeeded > 0 { - continue - } if latestJob == nil || job.CreationTimestamp.After(latestJob.CreationTimestamp.Time) { latestJob = &jobList.Items[i] } } - return latestJob, nil + return latestJob, len(jobList.Items), nil } func getModelStatusFromJobStatus(jobStatus batchv1.JobStatus) v1alpha1api.ModelStatus { @@ -224,7 +222,7 @@ func (c *LocalModelNodeReconciler) downloadModels(ctx context.Context, localMode continue } } - job, err = c.getLatestJob(ctx, modelInfo.ModelName, nodeName, false) + job, _, err = c.getLatestJob(ctx, modelInfo.ModelName, nodeName) if err != nil { c.Log.Error(err, "Failed to getLatestJob", "model", modelInfo.ModelName, "node", nodeName) return err @@ -238,10 +236,13 @@ func (c *LocalModelNodeReconciler) downloadModels(ctx context.Context, localMode return err } } + newStatus[modelInfo.ModelName] = getModelStatusFromJobStatus(job.Status) + c.Log.Info("model downloading status:", "model", modelInfo.ModelName, + "node", localModelNode.ObjectMeta.Name, "status", newStatus[modelInfo.ModelName]) } else { // Folder does not exist c.Log.Info("Model folder not found", "model", modelInfo.ModelName) - job, err = c.getLatestJob(ctx, modelInfo.ModelName, nodeName, true) + job, jobCount, err := c.getLatestJob(ctx, modelInfo.ModelName, nodeName) if err != nil { c.Log.Error(err, "Failed to getLatestJob", "model", modelInfo.ModelName, "node", nodeName) return err @@ -252,19 +253,18 @@ func (c *LocalModelNodeReconciler) downloadModels(ctx context.Context, localMode // Recreate job if it has been terminated because the model is missing locally // If the job has failed, we do not retry here because there are retries on the job. // To retry the download, users can manually fix the issue and delete the failed job. - if job == nil || job.Status.Succeeded > 0 { - c.Log.Info("Download model", "model", modelInfo.ModelName) + // Add the job count check for protection to ensure not creating more than 2 jobs including the previous one. + if job == nil || (job.Status.Succeeded > 0 && jobCount < 2) { job, err = c.launchJob(ctx, *localModelNode, modelInfo) if err != nil { - c.Log.Error(err, "Failed to create Job", "model", modelInfo.ModelName, "node", nodeName) + c.Log.Error(err, "Failed to create job", "model", modelInfo.ModelName, "node", nodeName) return err } } + newStatus[modelInfo.ModelName] = getModelStatusFromJobStatus(job.Status) + c.Log.Info("model downloading status:", "model", modelInfo.ModelName, + "node", localModelNode.ObjectMeta.Name, "status", newStatus[modelInfo.ModelName]) } - newStatus[modelInfo.ModelName] = getModelStatusFromJobStatus(job.Status) - - c.Log.Info("Downloading models:", "model", modelInfo.ModelName, - "node", localModelNode.ObjectMeta.Name, "status", newStatus[modelInfo.ModelName]) } // Skip update if no changes to status @@ -286,10 +286,6 @@ func (c *LocalModelNodeReconciler) downloadModels(ctx context.Context, localMode func (c *LocalModelNodeReconciler) deleteModels(localModelNode v1alpha1api.LocalModelNode) error { // 1. Scan model dir and get a list of existing folders representing downloaded models foldersToRemove := map[string]struct{}{} - if err := fsHelper.ensureModelRootFolderExists(); err != nil { - c.Log.Error(err, "Failed to ensure model root folder exists") - return err - } entries, err := fsHelper.getModelFolders() if err != nil { c.Log.Error(err, "Failed to list model folder") @@ -365,6 +361,11 @@ func (c *LocalModelNodeReconciler) Reconcile(ctx context.Context, req ctrl.Reque // fsHelper is a global variable to allow mocking in tests if fsHelper == nil { fsHelper = NewFileSystemHelper(modelsRootFolder) + // TODO we need a way to ensure that the local path on persistent volume is the same as the local path of the node agent DaemonSet. + err := fsHelper.ensureModelRootFolderExists() + if err != nil { + panic(fmt.Sprintf("Failed to ensure model root folder exists: %s", err.Error())) + } } // Create Jobs to download models if the model is not present locally. diff --git a/pkg/controller/v1alpha1/localmodelnode/file_utils.go b/pkg/controller/v1alpha1/localmodelnode/file_utils.go index 35565dd2ddd..2f584a768f9 100644 --- a/pkg/controller/v1alpha1/localmodelnode/file_utils.go +++ b/pkg/controller/v1alpha1/localmodelnode/file_utils.go @@ -39,12 +39,12 @@ func NewFileSystemHelper(modelsRootFolder string) *FileSystemHelper { } // should be used only in this struct -func (f *FileSystemHelper) getModelFolderPrivate(modelName string) string { - return filepath.Join(f.modelsRootFolder, modelName) +func getModelFolder(rootFolderName string, modelName string) string { + return filepath.Join(rootFolderName, modelName) } func (f *FileSystemHelper) removeModel(modelName string) error { - path := f.getModelFolderPrivate(modelName) + path := getModelFolder(f.modelsRootFolder, modelName) return os.RemoveAll(path) } @@ -53,7 +53,7 @@ func (f *FileSystemHelper) getModelFolders() ([]os.DirEntry, error) { } func (f *FileSystemHelper) hasModelFolder(modelName string) (bool, error) { - folder := f.getModelFolderPrivate(modelName) + folder := getModelFolder(f.modelsRootFolder, modelName) _, err := os.ReadDir(folder) if err == nil { return true, nil diff --git a/pkg/controller/v1beta1/inferenceservice/components/explainer.go b/pkg/controller/v1beta1/inferenceservice/components/explainer.go index 6e168070c45..666df1f597a 100644 --- a/pkg/controller/v1beta1/inferenceservice/components/explainer.go +++ b/pkg/controller/v1beta1/inferenceservice/components/explainer.go @@ -72,7 +72,7 @@ func (e *Explainer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro e.Log.Info("Reconciling Explainer", "ExplainerSpec", isvc.Spec.Explainer) explainer := isvc.Spec.Explainer.GetImplementation() annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(e.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) // KNative does not support INIT containers or mounting, so we add annotations that trigger the // StorageInitializer injector to mutate the underlying deployment to provision model data @@ -107,7 +107,7 @@ func (e *Explainer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro // Label filter will be handled in ksvc_reconciler explainerLabels := isvc.Spec.Explainer.Labels explainerAnnotations := utils.Filter(isvc.Spec.Explainer.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(e.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) // Labels and annotations priority: explainer component > isvc @@ -170,7 +170,7 @@ func (e *Explainer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro isvc.Status.PropagateRawStatus(v1beta1.ExplainerComponent, deployment, r.URL) } else { r := knative.NewKsvcReconciler(e.client, e.scheme, objectMeta, &isvc.Spec.Explainer.ComponentExtensionSpec, - &podSpec, isvc.Status.Components[v1beta1.ExplainerComponent]) + &podSpec, isvc.Status.Components[v1beta1.ExplainerComponent], e.inferenceServiceConfig.ServiceLabelDisallowedList) if err := controllerutil.SetControllerReference(isvc, r.Service, e.scheme); err != nil { return ctrl.Result{}, errors.Wrapf(err, "fails to set owner reference for explainer") diff --git a/pkg/controller/v1beta1/inferenceservice/components/predictor.go b/pkg/controller/v1beta1/inferenceservice/components/predictor.go index f3192ab6026..7740985c336 100644 --- a/pkg/controller/v1beta1/inferenceservice/components/predictor.go +++ b/pkg/controller/v1beta1/inferenceservice/components/predictor.go @@ -90,9 +90,12 @@ func (p *Predictor) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro } annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(p.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) + p.Log.V(1).Info("Predictor custom annotations", "annotations", p.inferenceServiceConfig.ServiceAnnotationDisallowedList) + p.Log.V(1).Info("Predictor custom labels", "labels", p.inferenceServiceConfig.ServiceLabelDisallowedList) + addLoggerAnnotations(isvc.Spec.Predictor.Logger, annotations) addBatcherAnnotations(isvc.Spec.Predictor.Batcher, annotations) // Add StorageSpec annotations so mutator will mount storage credentials to InferenceService's predictor @@ -229,7 +232,7 @@ func (p *Predictor) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro // Label filter will be handled in ksvc_reconciler sRuntimeLabels = sRuntime.ServingRuntimePodSpec.Labels sRuntimeAnnotations = utils.Filter(sRuntime.ServingRuntimePodSpec.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(p.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) } else { container = predictor.GetContainer(isvc.ObjectMeta, isvc.Spec.Predictor.GetExtensions(), p.inferenceServiceConfig) @@ -263,7 +266,7 @@ func (p *Predictor) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro // Label filter will be handled in ksvc_reconciler predictorLabels := isvc.Spec.Predictor.Labels predictorAnnotations := utils.Filter(isvc.Spec.Predictor.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(p.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) // Labels and annotations priority: predictor component > isvc > ServingRuntimePodSpec @@ -368,7 +371,7 @@ func (p *Predictor) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, erro } else { podLabelKey = constants.RevisionLabel r := knative.NewKsvcReconciler(p.client, p.scheme, objectMeta, &isvc.Spec.Predictor.ComponentExtensionSpec, - &podSpec, isvc.Status.Components[v1beta1.PredictorComponent]) + &podSpec, isvc.Status.Components[v1beta1.PredictorComponent], p.inferenceServiceConfig.ServiceLabelDisallowedList) if err := controllerutil.SetControllerReference(isvc, r.Service, p.scheme); err != nil { return ctrl.Result{}, errors.Wrapf(err, "fails to set owner reference for predictor") } diff --git a/pkg/controller/v1beta1/inferenceservice/components/transformer.go b/pkg/controller/v1beta1/inferenceservice/components/transformer.go index 2e632edf535..c96c671b177 100644 --- a/pkg/controller/v1beta1/inferenceservice/components/transformer.go +++ b/pkg/controller/v1beta1/inferenceservice/components/transformer.go @@ -73,7 +73,7 @@ func (p *Transformer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, er p.Log.Info("Reconciling Transformer", "TransformerSpec", isvc.Spec.Transformer) transformer := isvc.Spec.Transformer.GetImplementation() annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(p.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) // KNative does not support INIT containers or mounting, so we add annotations that trigger the // StorageInitializer injector to mutate the underlying deployment to provision model data @@ -109,7 +109,7 @@ func (p *Transformer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, er // Label filter will be handled in ksvc_reconciler transformerLabels := isvc.Spec.Transformer.Labels transformerAnnotations := utils.Filter(isvc.Spec.Transformer.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(p.inferenceServiceConfig.ServiceAnnotationDisallowedList, key) }) // Labels and annotations priority: transformer component > isvc @@ -199,7 +199,7 @@ func (p *Transformer) Reconcile(isvc *v1beta1.InferenceService) (ctrl.Result, er isvc.Status.PropagateRawStatus(v1beta1.TransformerComponent, deployment, r.URL) } else { r := knative.NewKsvcReconciler(p.client, p.scheme, objectMeta, &isvc.Spec.Transformer.ComponentExtensionSpec, - &podSpec, isvc.Status.Components[v1beta1.TransformerComponent]) + &podSpec, isvc.Status.Components[v1beta1.TransformerComponent], p.inferenceServiceConfig.ServiceLabelDisallowedList) if err := controllerutil.SetControllerReference(isvc, r.Service, p.scheme); err != nil { return ctrl.Result{}, errors.Wrapf(err, "fails to set owner reference for transformer") } diff --git a/pkg/controller/v1beta1/inferenceservice/controller.go b/pkg/controller/v1beta1/inferenceservice/controller.go index 6f3d262aade..ff89c18a16e 100644 --- a/pkg/controller/v1beta1/inferenceservice/controller.go +++ b/pkg/controller/v1beta1/inferenceservice/controller.go @@ -27,6 +27,7 @@ import ( istioclientv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" + netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/equality" apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -52,6 +53,7 @@ import ( modelconfig "github.com/kserve/kserve/pkg/controller/v1beta1/inferenceservice/reconcilers/modelconfig" isvcutils "github.com/kserve/kserve/pkg/controller/v1beta1/inferenceservice/utils" "github.com/kserve/kserve/pkg/utils" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) // +kubebuilder:rbac:groups=serving.kserve.io,resources=inferenceservices;inferenceservices/finalizers,verbs=get;list;watch;create;update;patch;delete @@ -79,7 +81,7 @@ import ( // +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch // +kubebuilder:rbac:groups=core,resources=events,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch -// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=get;list;watch +// +kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=httproutes,verbs=get;list;watch;create;update;patch;delete // InferenceServiceState describes the Readiness of the InferenceService type InferenceServiceState string @@ -111,9 +113,15 @@ func (r *InferenceServiceReconciler) Reconcile(ctx context.Context, req ctrl.Req } return reconcile.Result{}, err } + + isvcConfig, err := v1beta1api.NewInferenceServicesConfig(r.Clientset) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "fails to create InferenceServicesConfig") + } + // get annotations from isvc annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) }) deployConfig, err := v1beta1api.NewDeployConfig(r.Clientset) @@ -190,10 +198,6 @@ func (r *InferenceServiceReconciler) Reconcile(ctx context.Context, req ctrl.Req // Setup reconcilers r.Log.Info("Reconciling inference service", "apiVersion", isvc.APIVersion, "isvc", isvc.Name) - isvcConfig, err := v1beta1api.NewInferenceServicesConfig(r.Clientset) - if err != nil { - return reconcile.Result{}, errors.Wrapf(err, "fails to create InferenceServicesConfig") - } // Reconcile cabundleConfigMap caBundleConfigMapReconciler := cabundleconfigmap.NewCaBundleConfigMapReconciler(r.Client, r.Clientset, r.Scheme) @@ -246,15 +250,23 @@ func (r *InferenceServiceReconciler) Reconcile(ctx context.Context, req ctrl.Req // check raw deployment if deploymentMode == constants.RawDeployment { - reconciler, err := ingress.NewRawIngressReconciler(r.Client, r.Scheme, ingressConfig) - if err != nil { - return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") - } - if err := reconciler.Reconcile(isvc); err != nil { - return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") + if ingressConfig.EnableGatewayAPI { + reconciler := ingress.NewRawHTTPRouteReconciler(r.Client, r.Scheme, ingressConfig, isvcConfig) + + if err := reconciler.Reconcile(ctx, isvc); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") + } + } else { + reconciler, err := ingress.NewRawIngressReconciler(r.Client, r.Scheme, ingressConfig, isvcConfig) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") + } + if err := reconciler.Reconcile(isvc); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") + } } } else { - reconciler := ingress.NewIngressReconciler(r.Client, r.Clientset, r.Scheme, ingressConfig) + reconciler := ingress.NewIngressReconciler(r.Client, r.Clientset, r.Scheme, ingressConfig, isvcConfig) r.Log.Info("Reconciling ingress for inference service", "isvc", isvc.Name) if err := reconciler.Reconcile(isvc); err != nil { return reconcile.Result{}, errors.Wrapf(err, "fails to reconcile ingress") @@ -360,6 +372,22 @@ func (r *InferenceServiceReconciler) SetupWithManager(mgr ctrl.Manager, deployCo r.Log.Info("The InferenceService controller won't watch networking.istio.io/v1beta1/VirtualService resources because the CRD is not available.") } + if ingressConfig.EnableGatewayAPI { + gatewayapiFound, err := utils.IsCrdAvailable(r.ClientConfig, gatewayapiv1.GroupVersion.String(), constants.HTTPRouteKind) + if err != nil { + return err + } + + if gatewayapiFound { + ctrlBuilder = ctrlBuilder.Owns(&gatewayapiv1.HTTPRoute{}) + } else { + r.Log.Info("The InferenceService controller won't watch gateway.networking.k8s.io/v1/HTTPRoute resources because the CRD is not available.") + panic("Gateway API CRD not available") + } + } else { + ctrlBuilder = ctrlBuilder.Owns(&netv1.Ingress{}) + } + return ctrlBuilder.Complete(r) } diff --git a/pkg/controller/v1beta1/inferenceservice/controller_test.go b/pkg/controller/v1beta1/inferenceservice/controller_test.go index 39a8fcf6ff0..da36c489778 100644 --- a/pkg/controller/v1beta1/inferenceservice/controller_test.go +++ b/pkg/controller/v1beta1/inferenceservice/controller_test.go @@ -75,6 +75,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } }`, "ingress": `{ + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway": "knative-serving/knative-ingress-gateway", "localGateway": "knative-serving/knative-local-gateway", "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local" @@ -1932,6 +1933,7 @@ var _ = Describe("v1beta1 inference service controller", func() { for key, value := range configs { if key == "ingress" { copiedConfigs[key] = `{ + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "disableIstioVirtualHost": true, "ingressGateway": "knative-serving/knative-ingress-gateway", "localGateway": "knative-serving/knative-local-gateway", diff --git a/pkg/controller/v1beta1/inferenceservice/rawkube_controller_test.go b/pkg/controller/v1beta1/inferenceservice/rawkube_controller_test.go index 23303fc5a04..2b6a55b4e75 100644 --- a/pkg/controller/v1beta1/inferenceservice/rawkube_controller_test.go +++ b/pkg/controller/v1beta1/inferenceservice/rawkube_controller_test.go @@ -22,25 +22,19 @@ import ( "time" - "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" - "github.com/kserve/kserve/pkg/utils" - apierr "k8s.io/apimachinery/pkg/api/errors" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kserve/kserve/pkg/apis/serving/v1beta1" - "github.com/kserve/kserve/pkg/constants" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "google.golang.org/protobuf/proto" appsv1 "k8s.io/api/apps/v1" - autoscalingv2 "k8s.io/api/autoscaling/v2" v1 "k8s.io/api/core/v1" v1beta1utils "github.com/kserve/kserve/pkg/controller/v1beta1/inferenceservice/utils" routev1 "github.com/openshift/api/route/v1" netv1 "k8s.io/api/networking/v1" + apierr "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -48,12 +42,18 @@ import ( "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "sigs.k8s.io/controller-runtime/pkg/reconcile" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" + "github.com/kserve/kserve/pkg/apis/serving/v1beta1" + "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" ) var _ = Describe("v1beta1 inference service controller", func() { // Define utility constants for object names and testing timeouts/durations and intervals. const ( - timeout = time.Second * 10 + timeout = time.Second * 60 interval = time.Millisecond * 250 domain = "example.com" ) @@ -68,6 +68,7 @@ var _ = Describe("v1beta1 inference service controller", func() { v1.ResourceMemory: resource.MustParse("2Gi"), }, } + kserveGateway = types.NamespacedName{Name: "kserve-ingress-gateway", Namespace: "kserve"} ) Context("When creating inference service with raw kube predictor", func() { @@ -79,9 +80,12 @@ var _ = Describe("v1beta1 inference service controller", func() { } }`, "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", "ingressGateway": "knative-serving/knative-ingress-gateway", "localGateway": "knative-serving/knative-local-gateway", - "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local" + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"] }`, "storageInitializer": `{ "image" : "kserve/storage-initializer:latest", @@ -95,7 +99,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }`, } - It("Should have ingress/service/deployment/hpa created", func() { + It("Should have httproute/service/deployment/httproute created", func() { By("By creating a new InferenceService") // Create configmap var configMap = &v1.ConfigMap{ @@ -161,8 +165,9 @@ var _ = Describe("v1beta1 inference service controller", func() { Spec: v1beta1.InferenceServiceSpec{ Predictor: v1beta1.PredictorSpec{ ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ - MinReplicas: v1beta1.GetIntReference(1), - MaxReplicas: 3, + MinReplicas: v1beta1.GetIntReference(1), + MaxReplicas: 3, + TimeoutSeconds: utils.ToPointer(int64(30)), }, Tensorflow: &v1beta1.TFServingSpec{ PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ @@ -179,6 +184,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) inferenceService := &v1beta1.InferenceService{} @@ -291,7 +297,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ProgressDeadlineSeconds: &progressDeadlineSeconds, }, } - Expect(actualDeployment.Spec).To(Equal(expectedDeployment.Spec)) + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) //check service actualService := &v1.Service{} @@ -326,7 +332,7 @@ var _ = Describe("v1beta1 inference service controller", func() { actualService.Spec.IPFamilies = nil actualService.Spec.IPFamilyPolicy = nil actualService.Spec.InternalTrafficPolicy = nil - Expect(actualService.Spec).To(Equal(expectedService.Spec)) + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) //check isvc status updatedDeployment := actualDeployment.DeepCopy() @@ -338,62 +344,175 @@ var _ = Describe("v1beta1 inference service controller", func() { } Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) - //check ingress - pathType := netv1.PathTypePrefix - actualIngress := &netv1.Ingress{} - predictorIngressKey := types.NamespacedName{Name: serviceKey.Name, - Namespace: serviceKey.Namespace} - Eventually(func() error { return k8sClient.Get(context.TODO(), predictorIngressKey, actualIngress) }, timeout). - Should(Succeed()) - expectedIngress := netv1.Ingress{ - Spec: netv1.IngressSpec{ - Rules: []netv1.IngressRule{ + //check http route + actualTopLevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualTopLevelHttpRoute) + }, timeout).Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedTopLevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: "raw-foo-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), }, + Weight: utils.ToPointer(int32(1)), }, }, }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, }, + }, + }, + } + Expect(actualTopLevelHttpRoute.Spec).To(BeComparableTo(expectedTopLevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout).Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: "raw-foo-predictor-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), }, + Weight: utils.ToPointer(int32(1)), }, }, }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, }, }, }, } - Expect(actualIngress.Spec).To(Equal(expectedIngress.Spec)) + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualTopLevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualTopLevelHttpRoute)).NotTo(HaveOccurred()) + // verify if InferenceService status is updated expectedIsvcStatus := v1beta1.InferenceServiceStatus{ Status: duckv1.Status{ @@ -451,7 +570,7 @@ var _ = Describe("v1beta1 inference service controller", func() { var stabilizationWindowSeconds int32 = 0 selectPolicy := autoscalingv2.MaxChangePolicySelect actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} - predictorHPAKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, Namespace: serviceKey.Namespace} Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). Should(Succeed()) @@ -460,7 +579,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ APIVersion: "apps/v1", Kind: "Deployment", - Name: constants.PredictorServiceName(serviceKey.Name), + Name: predictorServiceKey.Name, }, MinReplicas: &minReplicas, MaxReplicas: maxReplicas, @@ -507,9 +626,9 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, } - Expect(actualHPA.Spec).To(Equal(expectedHPA.Spec)) + Expect(actualHPA.Spec).To(BeComparableTo(expectedHPA.Spec)) }) - It("Should have ingress/service/deployment/hpa created with DeploymentStrategy", func() { + It("Should have httproute/service/deployment/hpa created with DeploymentStrategy", func() { By("By creating a new InferenceService with DeploymentStrategy in PredictorSpec") // Create configmap var configMap = &v1.ConfigMap{ @@ -601,6 +720,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) inferenceService := &v1beta1.InferenceService{} @@ -706,7 +826,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ProgressDeadlineSeconds: &progressDeadlineSeconds, }, } - Expect(actualDeployment.Spec).To(Equal(expectedDeployment.Spec)) + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) //check service actualService := &v1.Service{} @@ -741,7 +861,7 @@ var _ = Describe("v1beta1 inference service controller", func() { actualService.Spec.IPFamilies = nil actualService.Spec.IPFamilyPolicy = nil actualService.Spec.InternalTrafficPolicy = nil - Expect(actualService.Spec).To(Equal(expectedService.Spec)) + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) //check isvc status updatedDeployment := actualDeployment.DeepCopy() @@ -753,62 +873,177 @@ var _ = Describe("v1beta1 inference service controller", func() { } Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) - //check ingress - pathType := netv1.PathTypePrefix - actualIngress := &netv1.Ingress{} - predictorIngressKey := types.NamespacedName{Name: serviceKey.Name, - Namespace: serviceKey.Namespace} - Eventually(func() error { return k8sClient.Get(context.TODO(), predictorIngressKey, actualIngress) }, timeout). + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). Should(Succeed()) - expectedIngress := netv1.Ingress{ - Spec: netv1.IngressSpec{ - Rules: []netv1.IngressRule{ + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: "raw-foo-customized-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-customized-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, }, }, }, }, }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: "raw-foo-customized-predictor-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-customized-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, }, }, }, }, }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, }, }, }, } - Expect(actualIngress.Spec).To(Equal(expectedIngress.Spec)) + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + // verify if InferenceService status is updated expectedIsvcStatus := v1beta1.InferenceServiceStatus{ Status: duckv1.Status{ @@ -866,7 +1101,7 @@ var _ = Describe("v1beta1 inference service controller", func() { var stabilizationWindowSeconds int32 = 0 selectPolicy := autoscalingv2.MaxChangePolicySelect actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} - predictorHPAKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, Namespace: serviceKey.Namespace} Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). Should(Succeed()) @@ -875,7 +1110,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ APIVersion: "apps/v1", Kind: "Deployment", - Name: constants.PredictorServiceName(serviceKey.Name), + Name: predictorServiceKey.Name, }, MinReplicas: &minReplicas, MaxReplicas: maxReplicas, @@ -922,9 +1157,9 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, } - Expect(actualHPA.Spec).To(Equal(expectedHPA.Spec)) + Expect(actualHPA.Spec).To(BeComparableTo(expectedHPA.Spec)) }) - It("Should have ingress/service/deployment created", func() { + It("Should have httproute/service/deployment created", func() { By("By creating a new InferenceService with AutoscalerClassExternal") // Create configmap var configMap = &v1.ConfigMap{ @@ -1002,6 +1237,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) inferenceService := &v1beta1.InferenceService{} @@ -1112,7 +1348,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ProgressDeadlineSeconds: &progressDeadlineSeconds, }, } - Expect(actualDeployment.Spec).To(Equal(expectedDeployment.Spec)) + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) //check service actualService := &v1.Service{} @@ -1147,7 +1383,7 @@ var _ = Describe("v1beta1 inference service controller", func() { actualService.Spec.IPFamilies = nil actualService.Spec.IPFamilyPolicy = nil actualService.Spec.InternalTrafficPolicy = nil - Expect(actualService.Spec).To(Equal(expectedService.Spec)) + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) //check isvc status updatedDeployment := actualDeployment.DeepCopy() @@ -1159,65 +1395,180 @@ var _ = Describe("v1beta1 inference service controller", func() { } Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) - //check ingress - pathType := netv1.PathTypePrefix - actualIngress := &netv1.Ingress{} - predictorIngressKey := types.NamespacedName{Name: serviceKey.Name, - Namespace: serviceKey.Namespace} - Eventually(func() error { return k8sClient.Get(context.TODO(), predictorIngressKey, actualIngress) }, timeout). + //check http Route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). Should(Succeed()) - expectedIngress := netv1.Ingress{ - Spec: netv1.IngressSpec{ - Rules: []netv1.IngressRule{ + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: "raw-foo-2-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-2-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, }, }, }, }, }, - }, - { - Host: "raw-foo-2-predictor-default.example.com", - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: "raw-foo-2-predictor", - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, - }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), }, + Weight: utils.ToPointer(int32(1)), }, }, }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, }, }, }, } - Expect(actualIngress.Spec).To(Equal(expectedIngress.Spec)) - // verify if InferenceService status is updated - expectedIsvcStatus := v1beta1.InferenceServiceStatus{ - Status: duckv1.Status{ + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ Conditions: duckv1.Conditions{ { Type: v1beta1.IngressReady, @@ -1271,112 +1622,33 @@ var _ = Describe("v1beta1 inference service controller", func() { Namespace: serviceKey.Namespace} Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). Should(HaveOccurred()) - }) - It("Should have no ingress created if labeled as cluster-local", func() { - By("By creating a new InferenceService") - // Create configmap - var configMap = &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.InferenceServiceConfigMapName, - Namespace: constants.KServeNamespace, - }, - Data: configs, - } - Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) - defer k8sClient.Delete(context.TODO(), configMap) - // Create ServingRuntime - servingRuntime := &v1alpha1.ServingRuntime{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tf-serving-raw", - Namespace: "default", - }, - Spec: v1alpha1.ServingRuntimeSpec{ - SupportedModelFormats: []v1alpha1.SupportedModelFormat{ - { - Name: "tensorflow", - Version: proto.String("1"), - AutoSelect: proto.Bool(true), - }, - }, - ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ - Containers: []v1.Container{ - { - Name: "kserve-container", - Image: "tensorflow/serving:1.14.0", - Command: []string{"/usr/bin/tensorflow_model_server"}, - Args: []string{ - "--port=9000", - "--rest_api_port=8080", - "--model_base_path=/mnt/models", - "--rest_api_timeout_in_ms=60000", - }, - Resources: defaultResource, - }, - }, - }, - Disabled: proto.Bool(false), - }, + + // Replica should not be nil and it should be set to minReplicas if it was set. + updated_isvc := &v1beta1.InferenceService{} + + Eventually(func() error { + return k8sClient.Get(ctx, serviceKey, updated_isvc) + }, timeout, interval).Should(Succeed()) + if updated_isvc.Labels == nil { + updated_isvc.Labels = make(map[string]string) } - k8sClient.Create(context.TODO(), servingRuntime) - defer k8sClient.Delete(context.TODO(), servingRuntime) - serviceName := "raw-cluster-local" - var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: "default"}} - var serviceKey = expectedRequest.NamespacedName - var storageUri = "s3://test/mnist/export" - ctx := context.Background() - isvc := &v1beta1.InferenceService{ - ObjectMeta: metav1.ObjectMeta{ - Name: serviceKey.Name, - Namespace: serviceKey.Namespace, - Annotations: map[string]string{ - "serving.kserve.io/deploymentMode": "RawDeployment", - "serving.kserve.io/autoscalerClass": "hpa", - "serving.kserve.io/metrics": "cpu", - "serving.kserve.io/targetUtilizationPercentage": "75", - }, - Labels: map[string]string{ - "networking.kserve.io/visibility": "cluster-local", - }, - }, - Spec: v1beta1.InferenceServiceSpec{ - Predictor: v1beta1.PredictorSpec{ - ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ - MinReplicas: v1beta1.GetIntReference(1), - MaxReplicas: 3, - }, - Tensorflow: &v1beta1.TFServingSpec{ - PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ - StorageURI: &storageUri, - RuntimeVersion: proto.String("1.14.0"), - Container: v1.Container{ - Name: constants.InferenceServiceContainerName, - Resources: defaultResource, - }, - }, - }, - }, - }, + updated_isvc.Spec.Predictor.ComponentExtensionSpec = v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(2), } - isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) - Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) - - inferenceService := &v1beta1.InferenceService{} + Expect(k8sClient.Update(context.TODO(), updated_isvc)).NotTo(HaveOccurred()) + updatedDeployment_isvc_updated := &appsv1.Deployment{} Eventually(func() bool { - err := k8sClient.Get(ctx, serviceKey, inferenceService) - if err != nil { + if err := k8sClient.Get(context.TODO(), predictorDeploymentKey, updatedDeployment_isvc_updated); err == nil { + return updatedDeployment_isvc_updated.Spec.Replicas != nil && *updatedDeployment_isvc_updated.Spec.Replicas == 2 + } else { return false } - return true }, timeout, interval).Should(BeTrue()) - actualIngress := &netv1.Ingress{} - predictorIngressKey := types.NamespacedName{Name: serviceKey.Name, - Namespace: serviceKey.Namespace} - Consistently(func() error { return k8sClient.Get(context.TODO(), predictorIngressKey, actualIngress) }, timeout). - ShouldNot(Succeed()) + }) }) - Context("When creating inference service with raw kube predictor and empty ingressClassName", func() { + Context("When creating inference service with raw kube predictor and ingress creation disabled", func() { configs := map[string]string{ "explainers": `{ "alibi": { @@ -1385,14 +1657,17 @@ var _ = Describe("v1beta1 inference service controller", func() { } }`, "ingress": `{ - "ingressGateway": "knative-serving/knative-ingress-gateway", - "localGateway": "knative-serving/knative-local-gateway", - "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", - "ingressDomain": "example.com" - }`, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "ingressDomain": "example.com", + "additionalIngressDomains": ["additional.example.com"], + "disableIngressCreation": true + }`, } - It("Should have ingress/service/deployment/hpa created", func() { + It("Should have service/deployment/hpa created and http route should not be created", func() { By("By creating a new InferenceService") // Create configmap var configMap = &v1.ConfigMap{ @@ -1477,6 +1752,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) inferenceService := &v1beta1.InferenceService{} @@ -1589,7 +1865,7 @@ var _ = Describe("v1beta1 inference service controller", func() { ProgressDeadlineSeconds: &progressDeadlineSeconds, }, } - Expect(actualDeployment.Spec).To(Equal(expectedDeployment.Spec)) + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) //check service actualService := &v1.Service{} @@ -1624,7 +1900,7 @@ var _ = Describe("v1beta1 inference service controller", func() { actualService.Spec.IPFamilies = nil actualService.Spec.IPFamilyPolicy = nil actualService.Spec.InternalTrafficPolicy = nil - Expect(actualService.Spec).To(Equal(expectedService.Spec)) + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) //check isvc status updatedDeployment := actualDeployment.DeepCopy() @@ -1634,68 +1910,4843 @@ var _ = Describe("v1beta1 inference service controller", func() { Status: v1.ConditionTrue, }, } - Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) + Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) + + //check ingress not created + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Consistently(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Not(Succeed())) + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Consistently(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Not(Succeed())) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-default.example.com", serviceName), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-predictor-default.example.com", serviceName), + }, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check HPA + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). + Should(Succeed()) + expectedHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualHPA.Spec).To(BeComparableTo(expectedHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube predictor with domain template", func() { + configs := map[string]string{ + "explainers": `{ + "alibi": { + "image": "kfserving/alibi-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "ingressDomain": "example.com", + "domainTemplate": "{{ .Name }}.{{ .Namespace }}.{{ .IngressDomain }}", + "additionalIngressDomains": ["additional.example.com"] + }`, + } + + It("Should have httproute/service/deployment/hpa created", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + // Create InferenceService + serviceName := "model" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: "default"}} + var serviceKey = expectedRequest.NamespacedName + var storageUri = "s3://test/mnist/export" + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: v1beta1.GetIntReference(1), + MaxReplicas: 3, + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + }, + } + isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + actualDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) + + //check service + actualService := &v1.Service{} + predictorServiceKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualService) }, timeout). + Should(Succeed()) + + expectedService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: constants.PredictorServiceName(serviceName), + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", constants.PredictorServiceName(serviceName)), + }, + }, + } + actualService.Spec.ClusterIP = "" + actualService.Spec.ClusterIPs = nil + actualService.Spec.IPFamilies = nil + actualService.Spec.IPFamilyPolicy = nil + actualService.Spec.InternalTrafficPolicy = nil + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) + + //check isvc status + updatedDeployment := actualDeployment.DeepCopy() + updatedDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Succeed()) + topLevelHost := fmt.Sprintf("%s.%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s.%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s.%s.%s", serviceName, serviceKey.Namespace, domain), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + //URL: &apis.URL{ + // Scheme: "http", + // Host: fmt.Sprintf("%s-predictor-default.example.com", serviceName), + //}, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check HPA + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). + Should(Succeed()) + expectedHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualHPA.Spec).To(BeComparableTo(expectedHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube predictor and transformer", func() { + configs := map[string]string{ + "explainers": `{ + "alibi": { + "image": "kserve/alibi-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"] + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, + } + + It("Should have httproute/service/deployment/hpa created for transformer and predictor", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + serviceName := "raw-foo-trans" + namespace := "default" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: namespace}} + var serviceKey = expectedRequest.NamespacedName + var predictorServiceKey = types.NamespacedName{Name: constants.PredictorServiceName(serviceName), + Namespace: namespace} + var transformerServiceKey = types.NamespacedName{Name: constants.TransformerServiceName(serviceName), + Namespace: namespace} + var storageUri = "s3://test/mnist/export" + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var transformerMinReplicas int32 = 1 + var transformerMaxReplicas int32 = 2 + var transformerCpuUtilization int32 = 80 + var transformerStabilizationWindowSeconds int32 = 0 + transformerSelectPolicy := autoscalingv2.MaxChangePolicySelect + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(minReplicas)), + MaxReplicas: int(maxReplicas), + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + Transformer: &v1beta1.TransformerSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(transformerMinReplicas)), + MaxReplicas: int(transformerMaxReplicas), + ScaleTarget: utils.ToPointer(int(transformerCpuUtilization)), + TimeoutSeconds: utils.ToPointer(int64(30)), + }, + PodSpec: v1beta1.PodSpec{ + Containers: []v1.Container{ + { + Image: "transformer:v1", + Resources: defaultResource, + Args: []string{ + "--port=8080", + }, + }, + }, + }, + }, + }, + } + isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // check predictor deployment + actualPredictorDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualPredictorDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedPredictorDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualPredictorDeployment.Spec).To(BeComparableTo(expectedPredictorDeployment.Spec)) + + // check transformer deployment + actualTransformerDeployment := &appsv1.Deployment{} + transformerDeploymentKey := types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { + return k8sClient.Get(context.TODO(), transformerDeploymentKey, actualTransformerDeployment) + }, timeout). + Should(Succeed()) + expectedTransformerDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerDeploymentKey.Name, + Namespace: transformerDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + transformerDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + transformerDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Transformer.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "transformer:v1", + Name: constants.InferenceServiceContainerName, + Args: []string{ + "--port=8080", + "--model_name", + serviceKey.Name, + "--predictor_host", + fmt.Sprintf("%s.%s", predictorServiceKey.Name, predictorServiceKey.Namespace), + "--http_port", + "8080", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualTransformerDeployment.Spec).To(BeComparableTo(expectedTransformerDeployment.Spec)) + + //check predictor service + actualPredictorService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualPredictorService) }, timeout). + Should(Succeed()) + expectedPredictorService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: predictorServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", predictorServiceKey.Name), + }, + }, + } + actualPredictorService.Spec.ClusterIP = "" + actualPredictorService.Spec.ClusterIPs = nil + actualPredictorService.Spec.IPFamilies = nil + actualPredictorService.Spec.IPFamilyPolicy = nil + actualPredictorService.Spec.InternalTrafficPolicy = nil + Expect(actualPredictorService.Spec).To(BeComparableTo(expectedPredictorService.Spec)) + + //check transformer service + actualTransformerService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), transformerServiceKey, actualTransformerService) }, timeout). + Should(Succeed()) + expectedTransformerService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerServiceKey.Name, + Namespace: transformerServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: transformerServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", transformerServiceKey.Name), + }, + }, + } + actualTransformerService.Spec.ClusterIP = "" + actualTransformerService.Spec.ClusterIPs = nil + actualTransformerService.Spec.IPFamilies = nil + actualTransformerService.Spec.IPFamilyPolicy = nil + actualTransformerService.Spec.InternalTrafficPolicy = nil + Expect(actualTransformerService.Spec).To(BeComparableTo(expectedTransformerService.Spec)) + + // update deployment status to make isvc ready + updatedPredictorDeployment := actualPredictorDeployment.DeepCopy() + updatedPredictorDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedPredictorDeployment)).NotTo(HaveOccurred()) + updatedTransformerDeployment := actualTransformerDeployment.DeepCopy() + updatedTransformerDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedTransformerDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(transformerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + actualTransformerHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace}, actualTransformerHttpRoute) + }, timeout). + Should(Succeed()) + transformerHost := fmt.Sprintf("%s-%s.%s", transformerServiceKey.Name, serviceKey.Namespace, "example.com") + expectedTransformerHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(transformerHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(transformerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualTransformerHttpRoute.Spec).To(BeComparableTo(expectedTransformerHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualTransformerHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualTransformerHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + { + Type: v1beta1.TransformerReady, + Status: "True", + Severity: "Info", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", serviceKey.Name, serviceKey.Namespace), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s.%s.svc.cluster.local", transformerServiceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + v1beta1.TransformerComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", transformerServiceKey.Name, serviceKey.Namespace), + }, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check predictor HPA + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualPredictorHPA) }, timeout). + Should(Succeed()) + expectedPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualPredictorHPA.Spec).To(BeComparableTo(expectedPredictorHPA.Spec)) + + // check transformer HPA + actualTransformerHPA := &autoscalingv2.HorizontalPodAutoscaler{} + transformerHPAKey := types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), transformerHPAKey, actualTransformerHPA) }, timeout). + Should(Succeed()) + expectedTransformerHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: transformerServiceKey.Name, + }, + MinReplicas: &transformerMinReplicas, + MaxReplicas: transformerMaxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &transformerCpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &transformerStabilizationWindowSeconds, + SelectPolicy: &transformerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &transformerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualTransformerHPA.Spec).To(BeComparableTo(expectedTransformerHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube predictor and explainer", func() { + configs := map[string]string{ + "explainers": `{ + "art": { + "image": "kserve/art-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"] + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, + } + + It("Should have httproute/service/deployment/hpa created for explainer and predictor", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + serviceName := "raw-foo-exp" + namespace := "default" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: namespace}} + var serviceKey = expectedRequest.NamespacedName + var predictorServiceKey = types.NamespacedName{Name: constants.PredictorServiceName(serviceName), + Namespace: namespace} + var explainerServiceKey = types.NamespacedName{Name: constants.ExplainerServiceName(serviceName), + Namespace: namespace} + var storageUri = "s3://test/mnist/export" + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var explainerMinReplicas int32 = 1 + var explainerMaxReplicas int32 = 2 + var explainerCpuUtilization int32 = 80 + var explainerStabilizationWindowSeconds int32 = 0 + ExplainerSelectPolicy := autoscalingv2.MaxChangePolicySelect + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(minReplicas)), + MaxReplicas: int(maxReplicas), + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + Explainer: &v1beta1.ExplainerSpec{ + ART: &v1beta1.ARTExplainerSpec{ + Type: v1beta1.ARTSquareAttackExplainer, + ExplainerExtensionSpec: v1beta1.ExplainerExtensionSpec{ + Config: map[string]string{"nb_classes": "10"}, + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(explainerMinReplicas)), + MaxReplicas: int(explainerMaxReplicas), + ScaleTarget: utils.ToPointer(int(explainerCpuUtilization)), + TimeoutSeconds: utils.ToPointer(int64(30)), + }, + }, + }, + } + isvcConfig, err := v1beta1.NewInferenceServicesConfig(clientset) + Expect(err).NotTo(HaveOccurred()) + isvc.DefaultInferenceService(isvcConfig, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // check predictor deployment + actualPredictorDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualPredictorDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedPredictorDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualPredictorDeployment.Spec).To(BeComparableTo(expectedPredictorDeployment.Spec)) + + // check Explainer deployment + actualExplainerDeployment := &appsv1.Deployment{} + explainerDeploymentKey := types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { + return k8sClient.Get(context.TODO(), explainerDeploymentKey, actualExplainerDeployment) + }, timeout). + Should(Succeed()) + expectedExplainerDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerDeploymentKey.Name, + Namespace: explainerDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + explainerDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + explainerDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Explainer.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "kserve/art-explainer:latest", + Name: constants.InferenceServiceContainerName, + Args: []string{ + "--model_name", + serviceKey.Name, + "--http_port", + "8080", + "--predictor_host", + fmt.Sprintf("%s.%s", predictorServiceKey.Name, predictorServiceKey.Namespace), + "--adversary_type", + "SquareAttack", + "--nb_classes", + "10", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualExplainerDeployment.Spec).To(BeComparableTo(expectedExplainerDeployment.Spec)) + + //check predictor service + actualPredictorService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualPredictorService) }, timeout). + Should(Succeed()) + expectedPredictorService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: predictorServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", predictorServiceKey.Name), + }, + }, + } + actualPredictorService.Spec.ClusterIP = "" + actualPredictorService.Spec.ClusterIPs = nil + actualPredictorService.Spec.IPFamilies = nil + actualPredictorService.Spec.IPFamilyPolicy = nil + actualPredictorService.Spec.InternalTrafficPolicy = nil + Expect(actualPredictorService.Spec).To(BeComparableTo(expectedPredictorService.Spec)) + + //check Explainer service + actualExplainerService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), explainerServiceKey, actualExplainerService) }, timeout). + Should(Succeed()) + expectedExplainerService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerServiceKey.Name, + Namespace: explainerServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: explainerServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", explainerServiceKey.Name), + }, + }, + } + actualExplainerService.Spec.ClusterIP = "" + actualExplainerService.Spec.ClusterIPs = nil + actualExplainerService.Spec.IPFamilies = nil + actualExplainerService.Spec.IPFamilyPolicy = nil + actualExplainerService.Spec.InternalTrafficPolicy = nil + Expect(actualExplainerService.Spec).To(BeComparableTo(expectedExplainerService.Spec)) + + // update deployment status to make isvc ready + updatedPredictorDeployment := actualPredictorDeployment.DeepCopy() + updatedPredictorDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedPredictorDeployment)).NotTo(HaveOccurred()) + updatedExplainerDeployment := actualExplainerDeployment.DeepCopy() + updatedExplainerDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedExplainerDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout).Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.ExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(explainerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + actualExplainerHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace}, actualExplainerHttpRoute) + }, timeout). + Should(Succeed()) + explainerHost := fmt.Sprintf("%s-%s.%s", explainerServiceKey.Name, serviceKey.Namespace, "example.com") + expectedExplainerHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(explainerHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(explainerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualExplainerHttpRoute.Spec).To(BeComparableTo(expectedExplainerHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualExplainerHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualExplainerHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.ExplainerReady, + Status: "True", + Severity: "Info", + }, + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", serviceKey.Name, serviceKey.Namespace), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s.%s.svc.cluster.local", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + v1beta1.ExplainerComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", explainerServiceKey.Name, serviceKey.Namespace), + }, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check predictor HPA + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualPredictorHPA) }, timeout). + Should(Succeed()) + expectedPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualPredictorHPA.Spec).To(BeComparableTo(expectedPredictorHPA.Spec)) + + // check Explainer HPA + actualExplainerHPA := &autoscalingv2.HorizontalPodAutoscaler{} + explainerHPAKey := types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), explainerHPAKey, actualExplainerHPA) }, timeout). + Should(Succeed()) + expectedExplainerHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: explainerServiceKey.Name, + }, + MinReplicas: &explainerMinReplicas, + MaxReplicas: explainerMaxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &explainerCpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &explainerStabilizationWindowSeconds, + SelectPolicy: &ExplainerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &ExplainerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualExplainerHPA.Spec).To(BeComparableTo(expectedExplainerHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube path based routing predictor", func() { + configs := map[string]string{ + "explainers": `{ + "alibi": { + "image": "kserve/alibi-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"], + "ingressDomain": "example.com", + "pathTemplate": "/serving/{{ .Namespace }}/{{ .Name }}" + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, + } + + It("Should have httproute/service/deployment/hpa created", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + serviceName := "raw-foo-path" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: "default"}} + var serviceKey = expectedRequest.NamespacedName + var storageUri = "s3://test/mnist/export" + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: v1beta1.GetIntReference(1), + MaxReplicas: 3, + TimeoutSeconds: utils.ToPointer(int64(30)), + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + }, + } + isvc.DefaultInferenceService(nil, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + actualDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualDeployment.Spec).To(BeComparableTo(expectedDeployment.Spec)) + + //check service + actualService := &v1.Service{} + predictorServiceKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualService) }, timeout). + Should(Succeed()) + + expectedService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: constants.PredictorServiceName(serviceName), + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", constants.PredictorServiceName(serviceName)), + }, + }, + } + actualService.Spec.ClusterIP = "" + actualService.Spec.ClusterIPs = nil + actualService.Spec.IPFamilies = nil + actualService.Spec.IPFamilyPolicy = nil + actualService.Spec.InternalTrafficPolicy = nil + Expect(actualService.Spec).To(BeComparableTo(expectedService.Spec)) + + //check isvc status + updatedDeployment := actualDeployment.DeepCopy() + updatedDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + prefixUrlPath := fmt.Sprintf("/serving/%s/%s", serviceKey.Namespace, serviceKey.Name) + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com", "example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(prefixUrlPath + "/"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", serviceKey.Name, serviceKey.Namespace), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check HPA + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). + Should(Succeed()) + expectedHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualHPA.Spec).To(BeComparableTo(expectedHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube path based routing predictor and transformer", func() { + configs := map[string]string{ + "explainers": `{ + "alibi": { + "image": "kserve/alibi-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"], + "ingressDomain": "example.com", + "pathTemplate": "/serving/{{ .Namespace }}/{{ .Name }}" + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, + } + + It("Should have ingress/service/deployment/hpa created for transformer and predictor", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + serviceName := "raw-foo-trans-path" + namespace := "default" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: namespace}} + var serviceKey = expectedRequest.NamespacedName + var predictorServiceKey = types.NamespacedName{Name: constants.PredictorServiceName(serviceName), + Namespace: namespace} + var transformerServiceKey = types.NamespacedName{Name: constants.TransformerServiceName(serviceName), + Namespace: namespace} + var storageUri = "s3://test/mnist/export" + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var transformerMinReplicas int32 = 1 + var transformerMaxReplicas int32 = 2 + var transformerCpuUtilization int32 = 80 + var transformerStabilizationWindowSeconds int32 = 0 + transformerSelectPolicy := autoscalingv2.MaxChangePolicySelect + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(minReplicas)), + MaxReplicas: int(maxReplicas), + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + Transformer: &v1beta1.TransformerSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(transformerMinReplicas)), + MaxReplicas: int(transformerMaxReplicas), + ScaleTarget: utils.ToPointer(int(transformerCpuUtilization)), + TimeoutSeconds: utils.ToPointer(int64(30)), + }, + PodSpec: v1beta1.PodSpec{ + Containers: []v1.Container{ + { + Image: "transformer:v1", + Resources: defaultResource, + Args: []string{ + "--port=8080", + }, + }, + }, + }, + }, + }, + } + isvcConfig, err := v1beta1.NewInferenceServicesConfig(clientset) + Expect(err).NotTo(HaveOccurred()) + isvc.DefaultInferenceService(isvcConfig, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // check predictor deployment + actualPredictorDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualPredictorDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedPredictorDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualPredictorDeployment.Spec).To(BeComparableTo(expectedPredictorDeployment.Spec)) + + // check transformer deployment + actualTransformerDeployment := &appsv1.Deployment{} + transformerDeploymentKey := types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { + return k8sClient.Get(context.TODO(), transformerDeploymentKey, actualTransformerDeployment) + }, timeout). + Should(Succeed()) + expectedTransformerDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerDeploymentKey.Name, + Namespace: transformerDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + transformerDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + transformerDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Transformer.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "transformer:v1", + Name: constants.InferenceServiceContainerName, + Args: []string{ + "--port=8080", + "--model_name", + serviceKey.Name, + "--predictor_host", + fmt.Sprintf("%s.%s", predictorServiceKey.Name, predictorServiceKey.Namespace), + "--http_port", + "8080", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualTransformerDeployment.Spec).To(BeComparableTo(expectedTransformerDeployment.Spec)) + + //check predictor service + actualPredictorService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualPredictorService) }, timeout). + Should(Succeed()) + expectedPredictorService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: predictorServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", predictorServiceKey.Name), + }, + }, + } + actualPredictorService.Spec.ClusterIP = "" + actualPredictorService.Spec.ClusterIPs = nil + actualPredictorService.Spec.IPFamilies = nil + actualPredictorService.Spec.IPFamilyPolicy = nil + actualPredictorService.Spec.InternalTrafficPolicy = nil + Expect(actualPredictorService.Spec).To(BeComparableTo(expectedPredictorService.Spec)) + + //check transformer service + actualTransformerService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), transformerServiceKey, actualTransformerService) }, timeout). + Should(Succeed()) + expectedTransformerService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: transformerServiceKey.Name, + Namespace: transformerServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: transformerServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", transformerServiceKey.Name), + }, + }, + } + actualTransformerService.Spec.ClusterIP = "" + actualTransformerService.Spec.ClusterIPs = nil + actualTransformerService.Spec.IPFamilies = nil + actualTransformerService.Spec.IPFamilyPolicy = nil + actualTransformerService.Spec.InternalTrafficPolicy = nil + Expect(actualTransformerService.Spec).To(BeComparableTo(expectedTransformerService.Spec)) + + // update deployment status to make isvc ready + updatedPredictorDeployment := actualPredictorDeployment.DeepCopy() + updatedPredictorDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedPredictorDeployment)).NotTo(HaveOccurred()) + updatedTransformerDeployment := actualTransformerDeployment.DeepCopy() + updatedTransformerDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedTransformerDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + prefixUrlPath := fmt.Sprintf("/serving/%s/%s", serviceKey.Namespace, serviceKey.Name) + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com", "example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(transformerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(prefixUrlPath + "/"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(transformerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) + + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). + Should(Succeed()) + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + actualTransformerHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace}, actualTransformerHttpRoute) + }, timeout). + Should(Succeed()) + transformerHost := fmt.Sprintf("%s-%s.%s", transformerServiceKey.Name, serviceKey.Namespace, "example.com") + expectedTransformerHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(transformerHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(transformerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualTransformerHttpRoute.Spec).To(BeComparableTo(expectedTransformerHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + }, + } + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualTransformerHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualTransformerHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + + // verify if InferenceService status is updated + expectedIsvcStatus := v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: duckv1.Conditions{ + { + Type: v1beta1.IngressReady, + Status: "True", + }, + { + Type: v1beta1.PredictorReady, + Status: "True", + }, + { + Type: apis.ConditionReady, + Status: "True", + }, + { + Type: v1beta1.TransformerReady, + Status: "True", + Severity: "Info", + }, + }, + }, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", serviceKey.Name, serviceKey.Namespace), + }, + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s.%s.svc.cluster.local", transformerServiceKey.Name, serviceKey.Namespace), + }, + }, + Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + v1beta1.TransformerComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", transformerServiceKey.Name, serviceKey.Namespace), + }, + }, + }, + ModelStatus: v1beta1.ModelStatus{ + TransitionStatus: "InProgress", + ModelRevisionStates: &v1beta1.ModelRevisionStates{TargetModelState: "Pending"}, + }, + } + Eventually(func() string { + isvc := &v1beta1.InferenceService{} + if err := k8sClient.Get(context.TODO(), serviceKey, isvc); err != nil { + return err.Error() + } + return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) + }, timeout).Should(BeEmpty()) + + //check predictor HPA + var cpuUtilization int32 = 75 + var stabilizationWindowSeconds int32 = 0 + selectPolicy := autoscalingv2.MaxChangePolicySelect + actualPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualPredictorHPA) }, timeout). + Should(Succeed()) + expectedPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: predictorServiceKey.Name, + }, + MinReplicas: &minReplicas, + MaxReplicas: maxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &cpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &stabilizationWindowSeconds, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &selectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualPredictorHPA.Spec).To(BeComparableTo(expectedPredictorHPA.Spec)) + + // check transformer HPA + actualTransformerHPA := &autoscalingv2.HorizontalPodAutoscaler{} + transformerHPAKey := types.NamespacedName{Name: transformerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), transformerHPAKey, actualTransformerHPA) }, timeout). + Should(Succeed()) + expectedTransformerHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: transformerServiceKey.Name, + }, + MinReplicas: &transformerMinReplicas, + MaxReplicas: transformerMaxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &transformerCpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &transformerStabilizationWindowSeconds, + SelectPolicy: &transformerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &transformerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualTransformerHPA.Spec).To(BeComparableTo(expectedTransformerHPA.Spec)) + }) + }) + Context("When creating inference service with raw kube path based routing predictor and explainer", func() { + configs := map[string]string{ + "explainers": `{ + "art": { + "image": "kserve/art-explainer", + "defaultImageVersion": "latest" + } + }`, + "ingress": `{ + "enableGatewayApi": true, + "kserveIngressGateway": "kserve/kserve-ingress-gateway", + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", + "additionalIngressDomains": ["additional.example.com"], + "ingressDomain": "example.com", + "pathTemplate": "/serving/{{ .Namespace }}/{{ .Name }}" + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, + } + + It("Should have httproute/service/deployment/hpa created for explainer and predictor", func() { + By("By creating a new InferenceService") + // Create configmap + var configMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.InferenceServiceConfigMapName, + Namespace: constants.KServeNamespace, + }, + Data: configs, + } + Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred()) + defer k8sClient.Delete(context.TODO(), configMap) + // Create ServingRuntime + servingRuntime := &v1alpha1.ServingRuntime{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tf-serving-raw", + Namespace: "default", + }, + Spec: v1alpha1.ServingRuntimeSpec{ + SupportedModelFormats: []v1alpha1.SupportedModelFormat{ + { + Name: "tensorflow", + Version: proto.String("1"), + AutoSelect: proto.Bool(true), + }, + }, + ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ + Containers: []v1.Container{ + { + Name: "kserve-container", + Image: "tensorflow/serving:1.14.0", + Command: []string{"/usr/bin/tensorflow_model_server"}, + Args: []string{ + "--port=9000", + "--rest_api_port=8080", + "--model_base_path=/mnt/models", + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + }, + }, + }, + Disabled: proto.Bool(false), + }, + } + k8sClient.Create(context.TODO(), servingRuntime) + defer k8sClient.Delete(context.TODO(), servingRuntime) + serviceName := "raw-foo-exp-path" + namespace := "default" + var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: namespace}} + var serviceKey = expectedRequest.NamespacedName + var predictorServiceKey = types.NamespacedName{Name: constants.PredictorServiceName(serviceName), + Namespace: namespace} + var explainerServiceKey = types.NamespacedName{Name: constants.ExplainerServiceName(serviceName), + Namespace: namespace} + var storageUri = "s3://test/mnist/export" + var minReplicas int32 = 1 + var maxReplicas int32 = 3 + var explainerMinReplicas int32 = 1 + var explainerMaxReplicas int32 = 2 + var explainerCpuUtilization int32 = 80 + var explainerStabilizationWindowSeconds int32 = 0 + ExplainerSelectPolicy := autoscalingv2.MaxChangePolicySelect + ctx := context.Background() + isvc := &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceKey.Name, + Namespace: serviceKey.Namespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(minReplicas)), + MaxReplicas: int(maxReplicas), + }, + Tensorflow: &v1beta1.TFServingSpec{ + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + RuntimeVersion: proto.String("1.14.0"), + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + }, + Explainer: &v1beta1.ExplainerSpec{ + ART: &v1beta1.ARTExplainerSpec{ + Type: v1beta1.ARTSquareAttackExplainer, + ExplainerExtensionSpec: v1beta1.ExplainerExtensionSpec{ + Config: map[string]string{"nb_classes": "10"}, + Container: v1.Container{ + Name: constants.InferenceServiceContainerName, + Resources: defaultResource, + }, + }, + }, + ComponentExtensionSpec: v1beta1.ComponentExtensionSpec{ + MinReplicas: utils.ToPointer(int(explainerMinReplicas)), + MaxReplicas: int(explainerMaxReplicas), + ScaleTarget: utils.ToPointer(int(explainerCpuUtilization)), + TimeoutSeconds: utils.ToPointer(int64(30)), + }, + }, + }, + } + isvcConfig, err := v1beta1.NewInferenceServicesConfig(clientset) + Expect(err).NotTo(HaveOccurred()) + isvc.DefaultInferenceService(isvcConfig, nil, &v1beta1.SecurityConfig{AutoMountServiceAccountToken: false}, nil) + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + defer k8sClient.Delete(ctx, isvc) + + inferenceService := &v1beta1.InferenceService{} + + Eventually(func() bool { + err := k8sClient.Get(ctx, serviceKey, inferenceService) + if err != nil { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // check predictor deployment + actualPredictorDeployment := &appsv1.Deployment{} + predictorDeploymentKey := types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorDeploymentKey, actualPredictorDeployment) }, timeout). + Should(Succeed()) + var replicas int32 = 1 + var revisionHistory int32 = 10 + var progressDeadlineSeconds int32 = 600 + var gracePeriod int64 = 30 + expectedPredictorDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: predictorDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + predictorDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Predictor.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + constants.StorageInitializerSourceUriInternalAnnotationKey: *isvc.Spec.Predictor.Model.StorageURI, + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tensorflow/serving:" + + *isvc.Spec.Predictor.Model.RuntimeVersion, + Name: constants.InferenceServiceContainerName, + Command: []string{v1beta1.TensorflowEntrypointCommand}, + Args: []string{ + "--port=" + v1beta1.TensorflowServingGRPCPort, + "--rest_api_port=" + v1beta1.TensorflowServingRestPort, + "--model_base_path=" + constants.DefaultModelLocalMountPath, + "--rest_api_timeout_in_ms=60000", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualPredictorDeployment.Spec).To(BeComparableTo(expectedPredictorDeployment.Spec)) + + // check Explainer deployment + actualExplainerDeployment := &appsv1.Deployment{} + explainerDeploymentKey := types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { + return k8sClient.Get(context.TODO(), explainerDeploymentKey, actualExplainerDeployment) + }, timeout). + Should(Succeed()) + expectedExplainerDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerDeploymentKey.Name, + Namespace: explainerDeploymentKey.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "isvc." + explainerDeploymentKey.Name, + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerDeploymentKey.Name, + Namespace: "default", + Labels: map[string]string{ + "app": "isvc." + explainerDeploymentKey.Name, + constants.KServiceComponentLabel: constants.Explainer.String(), + constants.InferenceServicePodLabelKey: serviceName, + }, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "hpa", + "serving.kserve.io/metrics": "cpu", + "serving.kserve.io/targetUtilizationPercentage": "75", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "kserve/art-explainer:latest", + Name: constants.InferenceServiceContainerName, + Args: []string{ + "--model_name", + serviceKey.Name, + "--http_port", + "8080", + "--predictor_host", + fmt.Sprintf("%s.%s", predictorServiceKey.Name, predictorServiceKey.Namespace), + "--adversary_type", + "SquareAttack", + "--nb_classes", + "10", + }, + Resources: defaultResource, + ReadinessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + TCPSocket: &v1.TCPSocketAction{ + Port: intstr.IntOrString{ + IntVal: 8080, + }, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", + }, + }, + SchedulerName: "default-scheduler", + RestartPolicy: "Always", + TerminationGracePeriodSeconds: &gracePeriod, + DNSPolicy: "ClusterFirst", + SecurityContext: &v1.PodSecurityContext{ + SELinuxOptions: nil, + WindowsOptions: nil, + RunAsUser: nil, + RunAsGroup: nil, + RunAsNonRoot: nil, + SupplementalGroups: nil, + FSGroup: nil, + Sysctls: nil, + FSGroupChangePolicy: nil, + SeccompProfile: nil, + }, + AutomountServiceAccountToken: proto.Bool(false), + }, + }, + Strategy: appsv1.DeploymentStrategy{ + Type: "RollingUpdate", + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "25%"}, + }, + }, + RevisionHistoryLimit: &revisionHistory, + ProgressDeadlineSeconds: &progressDeadlineSeconds, + }, + } + Expect(actualExplainerDeployment.Spec).To(BeComparableTo(expectedExplainerDeployment.Spec)) + + //check predictor service + actualPredictorService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorServiceKey, actualPredictorService) }, timeout). + Should(Succeed()) + expectedPredictorService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: predictorServiceKey.Name, + Namespace: predictorServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: predictorServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", predictorServiceKey.Name), + }, + }, + } + actualPredictorService.Spec.ClusterIP = "" + actualPredictorService.Spec.ClusterIPs = nil + actualPredictorService.Spec.IPFamilies = nil + actualPredictorService.Spec.IPFamilyPolicy = nil + actualPredictorService.Spec.InternalTrafficPolicy = nil + Expect(actualPredictorService.Spec).To(BeComparableTo(expectedPredictorService.Spec)) + + //check Explainer service + actualExplainerService := &v1.Service{} + Eventually(func() error { return k8sClient.Get(context.TODO(), explainerServiceKey, actualExplainerService) }, timeout). + Should(Succeed()) + expectedExplainerService := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: explainerServiceKey.Name, + Namespace: explainerServiceKey.Namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: explainerServiceKey.Name, + Protocol: "TCP", + Port: 80, + TargetPort: intstr.IntOrString{Type: 0, IntVal: 8080, StrVal: ""}, + }, + }, + Type: "ClusterIP", + SessionAffinity: "None", + Selector: map[string]string{ + "app": fmt.Sprintf("isvc.%s", explainerServiceKey.Name), + }, + }, + } + actualExplainerService.Spec.ClusterIP = "" + actualExplainerService.Spec.ClusterIPs = nil + actualExplainerService.Spec.IPFamilies = nil + actualExplainerService.Spec.IPFamilyPolicy = nil + actualExplainerService.Spec.InternalTrafficPolicy = nil + Expect(actualExplainerService.Spec).To(BeComparableTo(expectedExplainerService.Spec)) + + // update deployment status to make isvc ready + updatedPredictorDeployment := actualPredictorDeployment.DeepCopy() + updatedPredictorDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedPredictorDeployment)).NotTo(HaveOccurred()) + updatedExplainerDeployment := actualExplainerDeployment.DeepCopy() + updatedExplainerDeployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + } + Expect(k8sClient.Status().Update(context.TODO(), updatedExplainerDeployment)).NotTo(HaveOccurred()) + + //check http route + actualToplevelHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: serviceKey.Name, + Namespace: serviceKey.Namespace}, actualToplevelHttpRoute) + }, timeout). + Should(Succeed()) + topLevelHost := fmt.Sprintf("%s-%s.%s", serviceKey.Name, serviceKey.Namespace, "example.com") + prefixUrlPath := fmt.Sprintf("/serving/%s/%s", serviceKey.Namespace, serviceKey.Name) + expectedToplevelHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(topLevelHost), "additional.example.com", "example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.ExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(explainerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(prefixUrlPath + constants.PathBasedExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(explainerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(prefixUrlPath + "/"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + Weight: utils.ToPointer(int32(1)), + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualToplevelHttpRoute.Spec).To(BeComparableTo(expectedToplevelHttpRoute.Spec)) - //check ingress - pathType := netv1.PathTypePrefix - actualIngress := &netv1.Ingress{} - predictorIngressKey := types.NamespacedName{Name: serviceKey.Name, - Namespace: serviceKey.Namespace} - Eventually(func() error { return k8sClient.Get(context.TODO(), predictorIngressKey, actualIngress) }, timeout). + actualPredictorHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: predictorServiceKey.Name, + Namespace: serviceKey.Namespace}, actualPredictorHttpRoute) + }, timeout). Should(Succeed()) - expectedIngress := netv1.Ingress{ - Spec: netv1.IngressSpec{ - Rules: []netv1.IngressRule{ + predictorHost := fmt.Sprintf("%s-%s.%s", predictorServiceKey.Name, serviceKey.Namespace, "example.com") + expectedPredictorHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(predictorHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: fmt.Sprintf("%s-default.example.com", serviceName), - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: fmt.Sprintf("%s-predictor", serviceName), - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(predictorServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), }, + Weight: utils.ToPointer(int32(1)), }, }, }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, }, + }, + }, + } + Expect(actualPredictorHttpRoute.Spec).To(BeComparableTo(expectedPredictorHttpRoute.Spec)) + + actualExplainerHttpRoute := &gatewayapiv1.HTTPRoute{} + Eventually(func() error { + return k8sClient.Get(context.TODO(), types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace}, actualExplainerHttpRoute) + }, timeout). + Should(Succeed()) + explainerHost := fmt.Sprintf("%s-%s.%s", explainerServiceKey.Name, serviceKey.Namespace, "example.com") + expectedExplainerHttpRoute := gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{gatewayapiv1.Hostname(explainerHost)}, + Rules: []gatewayapiv1.HTTPRouteRule{ { - Host: fmt.Sprintf("%s-predictor-default.example.com", serviceName), - IngressRuleValue: netv1.IngressRuleValue{ - HTTP: &netv1.HTTPIngressRuleValue{ - Paths: []netv1.HTTPIngressPath{ - { - Path: "/", - PathType: &pathType, - Backend: netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: fmt.Sprintf("%s-predictor", serviceName), - Port: netv1.ServiceBackendPort{ - Number: 80, - }, - }, + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.FallbackPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: serviceKey.Name, }, + { + Name: constants.IsvcNamespaceHeader, + Value: serviceKey.Namespace, + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Group: (*gatewayapiv1.Group)(utils.ToPointer("")), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(explainerServiceKey.Name), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer(serviceKey.Namespace)), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), }, + Weight: utils.ToPointer(int32(1)), }, }, }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("30s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + }, + }, + }, + } + Expect(actualExplainerHttpRoute.Spec).To(BeComparableTo(expectedExplainerHttpRoute.Spec)) + + // Mark the Ingress as accepted to make isvc ready + httpRouteStatus := gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + ParentRef: gatewayapiv1.ParentReference{ + Name: gatewayapiv1.ObjectName(kserveGateway.Name), + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace(kserveGateway.Namespace)), + }, + ControllerName: "istio.io/gateway-controller", + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.ListenerConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "Route was valid", + LastTransitionTime: metav1.Now(), + }, + }, }, }, }, } - Expect(actualIngress.Spec).To(Equal(expectedIngress.Spec)) + actualPredictorHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualPredictorHttpRoute)).NotTo(HaveOccurred()) + actualExplainerHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualExplainerHttpRoute)).NotTo(HaveOccurred()) + actualToplevelHttpRoute.Status = httpRouteStatus + Expect(k8sClient.Status().Update(context.Background(), actualToplevelHttpRoute)).NotTo(HaveOccurred()) + // verify if InferenceService status is updated expectedIsvcStatus := v1beta1.InferenceServiceStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{ + { + Type: v1beta1.ExplainerReady, + Status: "True", + Severity: "Info", + }, { Type: v1beta1.IngressReady, Status: "True", @@ -1712,21 +6763,28 @@ var _ = Describe("v1beta1 inference service controller", func() { }, URL: &apis.URL{ Scheme: "http", - Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + Host: fmt.Sprintf("%s-%s.example.com", serviceKey.Name, serviceKey.Namespace), }, Address: &duckv1.Addressable{ URL: &apis.URL{ Scheme: "http", - Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + Host: fmt.Sprintf("%s.%s.svc.cluster.local", predictorServiceKey.Name, serviceKey.Namespace), }, }, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ v1beta1.PredictorComponent: { LatestCreatedRevision: "", - //URL: &apis.URL{ - // Scheme: "http", - // Host: fmt.Sprintf("%s-predictor-default.example.com", serviceName), - //}, + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", predictorServiceKey.Name, serviceKey.Namespace), + }, + }, + v1beta1.ExplainerComponent: { + LatestCreatedRevision: "", + URL: &apis.URL{ + Scheme: "http", + Host: fmt.Sprintf("%s-%s.example.com", explainerServiceKey.Name, serviceKey.Namespace), + }, }, }, ModelStatus: v1beta1.ModelStatus{ @@ -1742,23 +6800,21 @@ var _ = Describe("v1beta1 inference service controller", func() { return cmp.Diff(&expectedIsvcStatus, &isvc.Status, cmpopts.IgnoreTypes(apis.VolatileTime{})) }, timeout).Should(BeEmpty()) - //check HPA - var minReplicas int32 = 1 - var maxReplicas int32 = 3 + //check predictor HPA var cpuUtilization int32 = 75 var stabilizationWindowSeconds int32 = 0 selectPolicy := autoscalingv2.MaxChangePolicySelect - actualHPA := &autoscalingv2.HorizontalPodAutoscaler{} - predictorHPAKey := types.NamespacedName{Name: constants.PredictorServiceName(serviceKey.Name), + actualPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{} + predictorHPAKey := types.NamespacedName{Name: predictorServiceKey.Name, Namespace: serviceKey.Namespace} - Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualHPA) }, timeout). + Eventually(func() error { return k8sClient.Get(context.TODO(), predictorHPAKey, actualPredictorHPA) }, timeout). Should(Succeed()) - expectedHPA := &autoscalingv2.HorizontalPodAutoscaler{ + expectedPredictorHPA := &autoscalingv2.HorizontalPodAutoscaler{ Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ APIVersion: "apps/v1", Kind: "Deployment", - Name: constants.PredictorServiceName(serviceKey.Name), + Name: predictorServiceKey.Name, }, MinReplicas: &minReplicas, MaxReplicas: maxReplicas, @@ -1805,24 +6861,93 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, } - Expect(actualHPA.Spec).To(Equal(expectedHPA.Spec)) + Expect(actualPredictorHPA.Spec).To(BeComparableTo(expectedPredictorHPA.Spec)) + + // check Explainer HPA + actualExplainerHPA := &autoscalingv2.HorizontalPodAutoscaler{} + explainerHPAKey := types.NamespacedName{Name: explainerServiceKey.Name, + Namespace: serviceKey.Namespace} + Eventually(func() error { return k8sClient.Get(context.TODO(), explainerHPAKey, actualExplainerHPA) }, timeout). + Should(Succeed()) + expectedExplainerHPA := &autoscalingv2.HorizontalPodAutoscaler{ + Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: explainerServiceKey.Name, + }, + MinReplicas: &explainerMinReplicas, + MaxReplicas: explainerMaxReplicas, + Metrics: []autoscalingv2.MetricSpec{ + { + Type: autoscalingv2.ResourceMetricSourceType, + Resource: &autoscalingv2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: "Utilization", + AverageUtilization: &explainerCpuUtilization, + }, + }, + }, + }, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: &explainerStabilizationWindowSeconds, + SelectPolicy: &ExplainerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Pods", + Value: 4, + PeriodSeconds: 15, + }, + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + ScaleDown: &autoscalingv2.HPAScalingRules{ + StabilizationWindowSeconds: nil, + SelectPolicy: &ExplainerSelectPolicy, + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "Percent", + Value: 100, + PeriodSeconds: 15, + }, + }, + }, + }, + }, + } + Expect(actualExplainerHPA.Spec).To(BeComparableTo(expectedExplainerHPA.Spec)) }) }) - Context("When creating inference service with raw kube predictor with domain template", func() { + Context("When creating inference service with raw kube predictor with gateway api disabled", func() { configs := map[string]string{ "explainers": `{ - "alibi": { - "image": "kfserving/alibi-explainer", - "defaultImageVersion": "latest" - } - }`, + "alibi": { + "image": "kserve/alibi-explainer", + "defaultImageVersion": "latest" + } + }`, "ingress": `{ - "ingressGateway": "knative-serving/knative-ingress-gateway", - "localGateway": "knative-serving/knative-local-gateway", - "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local", - "ingressDomain": "example.com", - "domainTemplate": "{{ .Name }}.{{ .Namespace }}.{{ .IngressDomain }}" - }`, + "enableGatewayAPI": false, + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local" + }`, + "storageInitializer": `{ + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, } It("Should have ingress/service/deployment/hpa created", func() { @@ -1872,8 +6997,7 @@ var _ = Describe("v1beta1 inference service controller", func() { } k8sClient.Create(context.TODO(), servingRuntime) defer k8sClient.Delete(context.TODO(), servingRuntime) - // Create InferenceService - serviceName := "model" + serviceName := "raw-foo" var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: serviceName, Namespace: "default"}} var serviceKey = expectedRequest.NamespacedName var storageUri = "s3://test/mnist/export" @@ -2080,7 +7204,7 @@ var _ = Describe("v1beta1 inference service controller", func() { Spec: netv1.IngressSpec{ Rules: []netv1.IngressRule{ { - Host: fmt.Sprintf("%s.%s.%s", serviceName, serviceKey.Namespace, domain), + Host: "raw-foo-default.example.com", IngressRuleValue: netv1.IngressRuleValue{ HTTP: &netv1.HTTPIngressRuleValue{ Paths: []netv1.HTTPIngressPath{ @@ -2089,7 +7213,7 @@ var _ = Describe("v1beta1 inference service controller", func() { PathType: &pathType, Backend: netv1.IngressBackend{ Service: &netv1.IngressServiceBackend{ - Name: fmt.Sprintf("%s-predictor", serviceName), + Name: "raw-foo-predictor", Port: netv1.ServiceBackendPort{ Number: 80, }, @@ -2101,7 +7225,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, { - Host: fmt.Sprintf("%s-predictor.%s.%s", serviceName, serviceKey.Namespace, domain), + Host: "raw-foo-predictor-default.example.com", IngressRuleValue: netv1.IngressRuleValue{ HTTP: &netv1.HTTPIngressRuleValue{ Paths: []netv1.HTTPIngressPath{ @@ -2110,7 +7234,7 @@ var _ = Describe("v1beta1 inference service controller", func() { PathType: &pathType, Backend: netv1.IngressBackend{ Service: &netv1.IngressServiceBackend{ - Name: fmt.Sprintf("%s-predictor", serviceName), + Name: "raw-foo-predictor", Port: netv1.ServiceBackendPort{ Number: 80, }, @@ -2145,7 +7269,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, URL: &apis.URL{ Scheme: "http", - Host: fmt.Sprintf("%s-predictor.%s.svc.cluster.local", serviceKey.Name, serviceKey.Namespace), + Host: "raw-foo-default.example.com", }, Address: &duckv1.Addressable{ URL: &apis.URL{ @@ -2699,20 +7823,20 @@ var _ = Describe("v1beta1 inference service controller", func() { // Create a ConfigMap configs := map[string]string{ "ingress": `{ - "ingressGateway": "knative-serving/knative-ingress-gateway", - "localGateway": "knative-serving/knative-local-gateway", - "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local" - }`, + "ingressGateway": "knative-serving/knative-ingress-gateway", + "localGateway": "knative-serving/knative-local-gateway", + "localGatewayService": "knative-local-gateway.istio-system.svc.cluster.local" + }`, "storageInitializer": `{ - "image" : "kserve/storage-initializer:latest", - "memoryRequest": "100Mi", - "memoryLimit": "1Gi", - "cpuRequest": "100m", - "cpuLimit": "1", - "CaBundleConfigMapName": "", - "caBundleVolumeMountPath": "/etc/ssl/custom-certs", - "enableDirectPvcVolumeMount": false - }`, + "image" : "kserve/storage-initializer:latest", + "memoryRequest": "100Mi", + "memoryLimit": "1Gi", + "cpuRequest": "100m", + "cpuLimit": "1", + "CaBundleConfigMapName": "", + "caBundleVolumeMountPath": "/etc/ssl/custom-certs", + "enableDirectPvcVolumeMount": false + }`, } configMap := &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -2754,8 +7878,8 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, WorkerSpec: &v1alpha1.WorkerSpec{ - PipelineParallelSize: intPtr(2), - TensorParallelSize: intPtr(1), + PipelineParallelSize: utils.ToPointer(2), + TensorParallelSize: utils.ToPointer(1), ServingRuntimePodSpec: v1alpha1.ServingRuntimePodSpec{ Containers: []v1.Container{ { @@ -2830,7 +7954,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, timeout, interval).Should(BeTrue()) // Verify deployments details - verifyPipelineParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "2", int32Ptr(1)) + verifyPipelineParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "2", utils.ToPointer(int32(1))) // Check Services actualService := &v1.Service{} @@ -2898,7 +8022,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, WorkerSpec: &v1beta1.WorkerSpec{ - PipelineParallelSize: intPtr(3), + PipelineParallelSize: utils.ToPointer(3), }, }, }, @@ -2925,7 +8049,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, timeout, interval).Should(BeTrue()) // Verify deployments details - verifyPipelineParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "3", int32Ptr(2)) + verifyPipelineParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "3", utils.ToPointer(int32(2))) }) It("Should use WorkerSpec.TensorParallelSize value in isvc when it is set", func() { By("creating a new InferenceService") @@ -2955,7 +8079,7 @@ var _ = Describe("v1beta1 inference service controller", func() { }, }, WorkerSpec: &v1beta1.WorkerSpec{ - TensorParallelSize: intPtr(3), + TensorParallelSize: utils.ToPointer(3), }, }, }, @@ -2978,6 +8102,86 @@ var _ = Describe("v1beta1 inference service controller", func() { // Verify deployments details verifyTensorParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "3", constants.NvidiaGPUResourceType) }) + It("Should not set nil to replicas when multinode isvc(external autoscaler) is updated", func() { + By("creating a new InferenceService") + isvcName := "raw-huggingface-multinode-6" + predictorDeploymentName := constants.PredictorServiceName(isvcName) + workerDeploymentName := constants.PredictorWorkerServiceName(isvcName) + serviceKey = types.NamespacedName{Name: isvcName, Namespace: isvcNamespace} + + // Create a infereceService + isvc = &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: isvcName, + Namespace: isvcNamespace, + Annotations: map[string]string{ + "serving.kserve.io/deploymentMode": "RawDeployment", + "serving.kserve.io/autoscalerClass": "external", + }, + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{ + Model: &v1beta1.ModelSpec{ + ModelFormat: v1beta1.ModelFormat{ + Name: "huggingface", + }, + PredictorExtensionSpec: v1beta1.PredictorExtensionSpec{ + StorageURI: &storageUri, + }, + }, + WorkerSpec: &v1beta1.WorkerSpec{ + PipelineParallelSize: utils.ToPointer(3), + }, + }, + }, + } + Expect(k8sClient.Create(ctx, isvc)).Should(Succeed()) + DeferCleanup(func() { + k8sClient.Delete(ctx, isvc) + }) + + // Verify if predictor deployment (default deployment) is created + Eventually(func() bool { + return k8sClient.Get(ctx, types.NamespacedName{Name: predictorDeploymentName, Namespace: isvcNamespace}, actualDefaultDeployment) == nil + }, timeout, interval).Should(BeTrue()) + + // Verify if worker node deployment is created. + Eventually(func() bool { + return k8sClient.Get(ctx, types.NamespacedName{Name: workerDeploymentName, Namespace: isvcNamespace}, actualWorkerDeployment) == nil + }, timeout, interval).Should(BeTrue()) + + // Verify deployments details + verifyPipelineParallelSizeDeployments(actualDefaultDeployment, actualWorkerDeployment, "3", utils.ToPointer(int32(2))) + + // Update a infereceService + By("updating the InferenceService") + updatedIsvc := &v1beta1.InferenceService{} + k8sClient.Get(ctx, types.NamespacedName{Name: isvc.Name, Namespace: isvcNamespace}, updatedIsvc) + // Add label to isvc to create a new rs + if updatedIsvc.Labels == nil { + updatedIsvc.Labels = make(map[string]string) + } + updatedIsvc.Labels["newLabel"] = "test" + + err := k8sClient.Update(ctx, updatedIsvc) + Expect(err).ShouldNot(HaveOccurred(), "Failed to update InferenceService with new label") + + // Verify if predictor deployment (default deployment) has replicas + Eventually(func() bool { + if err := k8sClient.Get(ctx, types.NamespacedName{Name: predictorDeploymentName, Namespace: isvcNamespace}, actualDefaultDeployment); err == nil { + return actualDefaultDeployment.Spec.Replicas != nil && *actualDefaultDeployment.Spec.Replicas == 1 + } + return false + }, timeout, interval).Should(BeTrue()) + + // Verify if worker node deployment has replicas + Eventually(func() bool { + if err := k8sClient.Get(ctx, types.NamespacedName{Name: workerDeploymentName, Namespace: isvcNamespace}, actualWorkerDeployment); err == nil { + return actualWorkerDeployment.Spec.Replicas != nil && *actualWorkerDeployment.Spec.Replicas == 2 + } + return false + }, timeout, interval).Should(BeTrue()) + }) }) }) @@ -3013,10 +8217,3 @@ func verifyTensorParallelSizeDeployments(actualDefaultDeployment *appsv1.Deploym Expect(actualWorkerDeployment.Spec.Template.Spec.Containers[0].Resources.Limits[gpuResourceType]).Should(Equal(gpuResourceQuantity)) Expect(actualWorkerDeployment.Spec.Template.Spec.Containers[0].Resources.Requests[gpuResourceType]).Should(Equal(gpuResourceQuantity)) } -func int32Ptr(i int32) *int32 { - return &i -} - -func intPtr(i int) *int { - return &i -} diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler.go index cc43124ca9a..71062e73fc6 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler.go @@ -41,6 +41,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/utils/ptr" "knative.dev/pkg/kmp" kclient "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -184,6 +185,10 @@ func createRawDefaultDeployment(componentMeta metav1.ObjectMeta, deployment.Spec.Strategy = *componentExt.DeploymentStrategy } setDefaultDeploymentSpec(&deployment.Spec) + if componentExt.MinReplicas != nil && deployment.Annotations[constants.AutoscalerClass] == string(constants.AutoscalerClassExternal) { + deployment.Spec.Replicas = ptr.To(int32(*componentExt.MinReplicas)) + } + return deployment, nil } @@ -264,6 +269,14 @@ func createRawWorkerDeployment(componentMeta metav1.ObjectMeta, } setDefaultDeploymentSpec(&deployment.Spec) + // For multinode, it needs to keep original pods until new pods are ready with rollingUpdate strategy + if deployment.Spec.Strategy.Type == appsv1.RollingUpdateDeploymentStrategyType { + deployment.Spec.Strategy.RollingUpdate = &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: intstr.String, StrVal: "0%"}, + MaxSurge: &intstr.IntOrString{Type: intstr.String, StrVal: "100%"}, + } + } + deployment.Spec.Replicas = &replicas return deployment } @@ -405,7 +418,14 @@ func (r *DeploymentReconciler) checkDeploymentExist(client kclient.Client, deplo } // existed, check equivalence // for HPA scaling, we should ignore Replicas of Deployment - ignoreFields := cmpopts.IgnoreFields(appsv1.DeploymentSpec{}, "Replicas") + // for external scaler, we should not ignore Replicas. + var ignoreFields cmp.Option = nil // Initialize to nil by default + + // Set ignoreFields if the condition is met + if existingDeployment.Annotations[constants.AutoscalerClass] != string(constants.AutoscalerClassExternal) { + ignoreFields = cmpopts.IgnoreFields(appsv1.DeploymentSpec{}, "Replicas") + } + // Do a dry-run update. This will populate our local deployment object with any default values // that are present on the remote version. if err := client.Update(context.TODO(), deployment, kclient.DryRunAll); err != nil { @@ -572,8 +592,11 @@ func (r *DeploymentReconciler) Reconcile() ([]*appsv1.Deployment, error) { // To avoid the conflict between HPA and Deployment, // we need to remove the Replicas field from the deployment spec + // For external autoscaler, it should not remove replicas modDeployment := deployment.DeepCopy() - modDeployment.Spec.Replicas = nil + if modDeployment.Annotations[constants.AutoscalerClass] != string(constants.AutoscalerClassExternal) { + modDeployment.Spec.Replicas = nil + } modJson, err := json.Marshal(modDeployment) if err != nil { diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler_test.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler_test.go index c2f84f765e4..ae2d36cbe9b 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler_test.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/deployment/deployment_reconciler_test.go @@ -176,6 +176,13 @@ func TestCreateDefaultDeployment(t *testing.T) { constants.RawDeploymentAppLabel: "isvc.default-predictor", }, }, + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: intStrPtr("25%"), + MaxSurge: intStrPtr("25%"), + }, + }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: "default-predictor", @@ -242,6 +249,13 @@ func TestCreateDefaultDeployment(t *testing.T) { "app": "isvc.default-predictor", }, }, + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: intStrPtr("25%"), + MaxSurge: intStrPtr("25%"), + }, + }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: "default-predictor", @@ -316,6 +330,13 @@ func TestCreateDefaultDeployment(t *testing.T) { constants.RawDeploymentAppLabel: "isvc.default-predictor-worker", }, }, + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: intStrPtr("0%"), + MaxSurge: intStrPtr("100%"), + }, + }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: "worker-predictor", @@ -406,8 +427,6 @@ func TestCreateDefaultDeployment(t *testing.T) { cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.DNSPolicy"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.AutomountServiceAccountToken"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.SchedulerName"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.Type"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.RollingUpdate"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.RevisionHistoryLimit"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.ProgressDeadlineSeconds")); diff != "" { t.Errorf("Test %q unexpected deployment (-want +got): %v", tt.name, diff) @@ -484,8 +503,6 @@ func TestCreateDefaultDeployment(t *testing.T) { cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.DNSPolicy"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.AutomountServiceAccountToken"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.SchedulerName"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.Type"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.RollingUpdate"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.RevisionHistoryLimit"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.ProgressDeadlineSeconds")); diff != "" { t.Errorf("Test %q unexpected deployment (-want +got): %v", tt.name, diff) @@ -793,8 +810,6 @@ func TestCreateDefaultDeployment(t *testing.T) { cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.DNSPolicy"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.AutomountServiceAccountToken"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Template.Spec.SchedulerName"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.Type"), - cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.Strategy.RollingUpdate"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.RevisionHistoryLimit"), cmpopts.IgnoreFields(appsv1.Deployment{}, "Spec.ProgressDeadlineSeconds")); diff != "" { t.Errorf("Test %q unexpected deployment (-want +got): %v", tt.name, diff) @@ -804,6 +819,11 @@ func TestCreateDefaultDeployment(t *testing.T) { } } +func intStrPtr(s string) *intstr.IntOrString { + v := intstr.FromString(s) + return &v +} + func int32Ptr(i int32) *int32 { val := i return &val diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/domain.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/domain.go index 17a2671c2b5..e061c529e93 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/domain.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/domain.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" + "knative.dev/pkg/network" ) type DomainTemplateValues struct { @@ -62,3 +63,30 @@ func GenerateDomainName(name string, obj metav1.ObjectMeta, ingressConfig *v1bet return buf.String(), nil } + +func GenerateInternalDomainName(name string, obj metav1.ObjectMeta, ingressConfig *v1beta1.IngressConfig) (string, error) { + values := DomainTemplateValues{ + Name: name, + Namespace: obj.Namespace, + IngressDomain: network.GetClusterDomainName(), + Annotations: obj.Annotations, + Labels: obj.Labels, + } + + tpl, err := template.New("domain-template").Parse(ingressConfig.DomainTemplate) + if err != nil { + return "", err + } + + buf := bytes.Buffer{} + if err := tpl.Execute(&buf, values); err != nil { + return "", fmt.Errorf("error rendering the domain template: %w", err) + } + + urlErrs := validation.IsFullyQualifiedDomainName(field.NewPath("url"), buf.String()) + if urlErrs != nil { + return "", fmt.Errorf("invalid domain name %q: %w", buf.String(), urlErrs.ToAggregate()) + } + + return buf.String(), nil +} diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler.go new file mode 100644 index 00000000000..99239890ef2 --- /dev/null +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler.go @@ -0,0 +1,860 @@ +/* +Copyright 2024 The KServe Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ingress + +import ( + "context" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/apis" + knapis "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/network" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/kserve/kserve/pkg/apis/serving/v1beta1" + "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" +) + +const ( + HTTPRouteNotReady = "HttpRouteNotReady" + HTTPRouteParentStatusNotAvailable = "ParentStatusNotAvailable" +) + +var DefaultTimeout = toGatewayAPIDuration(60) + +type RawHTTPRouteReconciler struct { + client client.Client + scheme *runtime.Scheme + ingressConfig *v1beta1.IngressConfig + isvcConfig *v1beta1.InferenceServicesConfig +} + +func NewRawHTTPRouteReconciler(client client.Client, scheme *runtime.Scheme, ingressConfig *v1beta1.IngressConfig, + isvcConfig *v1beta1.InferenceServicesConfig) *RawHTTPRouteReconciler { + return &RawHTTPRouteReconciler{ + client: client, + scheme: scheme, + ingressConfig: ingressConfig, + isvcConfig: isvcConfig, + } +} + +// toGatewayAPIDuration converts seconds to gatewayapiv1.Duration +func toGatewayAPIDuration(seconds int64) *gatewayapiv1.Duration { + duration := gatewayapiv1.Duration(fmt.Sprintf("%ds", seconds)) + return &duration +} + +func createRawURL(isvc *v1beta1.InferenceService, + ingressConfig *v1beta1.IngressConfig) (*knapis.URL, error) { + var err error + url := &knapis.URL{} + url.Scheme = ingressConfig.UrlScheme + url.Host, err = GenerateDomainName(isvc.Name, isvc.ObjectMeta, ingressConfig) + if err != nil { + return nil, err + } + + return url, nil +} + +func getRawServiceHost(isvc *v1beta1.InferenceService, client client.Client) string { + existingService := &corev1.Service{} + if isvc.Spec.Transformer != nil { + transformerName := constants.TransformerServiceName(isvc.Name) + + // Check if existing transformer service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultTransformerServiceName(isvc.Name), Namespace: isvc.Namespace}, existingService) + if err == nil { + transformerName = constants.DefaultTransformerServiceName(isvc.Name) + } + return network.GetServiceHostname(transformerName, isvc.Namespace) + } + + predictorName := constants.PredictorServiceName(isvc.Name) + + // Check if existing predictor service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultPredictorServiceName(isvc.Name), Namespace: isvc.Namespace}, existingService) + if err == nil { + predictorName = constants.DefaultPredictorServiceName(isvc.Name) + } + return network.GetServiceHostname(predictorName, isvc.Namespace) +} + +func createHTTPRouteMatch(prefix string) gatewayapiv1.HTTPRouteMatch { + return gatewayapiv1.HTTPRouteMatch{ + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(prefix), + }, + } +} + +func addIsvcHeaders(name string, namespace string) gatewayapiv1.HTTPRouteFilter { + return gatewayapiv1.HTTPRouteFilter{ + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: name, + }, + { + Name: constants.IsvcNamespaceHeader, + Value: namespace, + }, + }, + }, + } +} + +func createHTTPRouteRule(routeMatches []gatewayapiv1.HTTPRouteMatch, filters []gatewayapiv1.HTTPRouteFilter, + serviceName, namespace string, port int32, timeout *gatewayapiv1.Duration) gatewayapiv1.HTTPRouteRule { + var backendRefs []gatewayapiv1.HTTPBackendRef + if serviceName != "" { + backendRefs = []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: gatewayapiv1.ObjectName(serviceName), + Namespace: (*gatewayapiv1.Namespace)(&namespace), + Port: (*gatewayapiv1.PortNumber)(&port), + }, + }, + }, + } + } + return gatewayapiv1.HTTPRouteRule{ + Matches: routeMatches, + Filters: filters, + BackendRefs: backendRefs, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: timeout, + }, + } +} + +func createRawPredictorHTTPRoute(isvc *v1beta1.InferenceService, ingressConfig *v1beta1.IngressConfig, isvcConfig *v1beta1.InferenceServicesConfig, + client client.Client) (*gatewayapiv1.HTTPRoute, error) { + var httpRouteRules []gatewayapiv1.HTTPRouteRule + var allowedHosts []gatewayapiv1.Hostname + + if !isvc.Status.IsConditionReady(v1beta1.PredictorReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Predictor ingress not created", + }) + return nil, nil + } + + existing := &corev1.Service{} + predictorName := constants.PredictorServiceName(isvc.Name) + + // Check if existing predictor service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultPredictorServiceName(isvc.Name), Namespace: isvc.Namespace}, existing) + if err == nil { + // Found existing predictor service with default suffix + predictorName = constants.DefaultPredictorServiceName(isvc.Name) + } + + // Add isvc name and namespace headers + filters := []gatewayapiv1.HTTPRouteFilter{addIsvcHeaders(isvc.Name, isvc.Namespace)} + + // Add predictor host rules + predictorHost, err := GenerateDomainName(predictorName, isvc.ObjectMeta, ingressConfig) + if err != nil { + return nil, fmt.Errorf("failed to generate predictor ingress host: %w", err) + } + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(predictorHost)) + routeMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.FallbackPrefix())} + timeout := DefaultTimeout + if isvc.Spec.Predictor.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Predictor.TimeoutSeconds) + } + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(routeMatch, filters, predictorName, isvc.Namespace, constants.CommonDefaultHttpPort, timeout)) + + annotations := utils.Filter(isvc.Annotations, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) + }) + labels := utils.Filter(isvc.Labels, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceLabelDisallowedList, key) + }) + gatewaySlice := strings.Split(ingressConfig.KserveIngressGateway, "/") + httpRoute := gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.PredictorServiceName(isvc.Name), + Namespace: isvc.Namespace, + Annotations: annotations, + Labels: labels, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: allowedHosts, + Rules: httpRouteRules, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(&gatewaySlice[0]), + Name: gatewayapiv1.ObjectName(gatewaySlice[1]), + }, + }, + }, + }, + } + return &httpRoute, nil +} + +func createRawTransformerHTTPRoute(isvc *v1beta1.InferenceService, ingressConfig *v1beta1.IngressConfig, isvcConfig *v1beta1.InferenceServicesConfig, + client client.Client) (*gatewayapiv1.HTTPRoute, error) { + var httpRouteRules []gatewayapiv1.HTTPRouteRule + var allowedHosts []gatewayapiv1.Hostname + + if !isvc.Status.IsConditionReady(v1beta1.TransformerReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Transformer ingress not created", + }) + return nil, nil + } + + existing := &corev1.Service{} + transformerName := constants.TransformerServiceName(isvc.Name) + + // Check if existing transformer service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultTransformerServiceName(isvc.Name), Namespace: isvc.Namespace}, existing) + if err == nil { + // Found existing transformer service with default suffix + transformerName = constants.DefaultTransformerServiceName(isvc.Name) + } + + // Add isvc name and namespace headers + filters := []gatewayapiv1.HTTPRouteFilter{addIsvcHeaders(isvc.Name, isvc.Namespace)} + + transformerHost, err := GenerateDomainName(transformerName, isvc.ObjectMeta, ingressConfig) + if err != nil { + return nil, fmt.Errorf("failed to generate transformer ingress host: %w", err) + } + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(transformerHost)) + routeMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.FallbackPrefix())} + timeout := DefaultTimeout + if isvc.Spec.Transformer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Transformer.TimeoutSeconds) + } + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(routeMatch, filters, transformerName, isvc.Namespace, + constants.CommonDefaultHttpPort, timeout)) + + annotations := utils.Filter(isvc.Annotations, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) + }) + labels := utils.Filter(isvc.Labels, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceLabelDisallowedList, key) + }) + gatewaySlice := strings.Split(ingressConfig.KserveIngressGateway, "/") + httpRoute := gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.TransformerServiceName(isvc.Name), + Namespace: isvc.Namespace, + Annotations: annotations, + Labels: labels, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: allowedHosts, + Rules: httpRouteRules, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(&gatewaySlice[0]), + Name: gatewayapiv1.ObjectName(gatewaySlice[1]), + }, + }, + }, + }, + } + return &httpRoute, nil +} + +func createRawExplainerHTTPRoute(isvc *v1beta1.InferenceService, ingressConfig *v1beta1.IngressConfig, isvcConfig *v1beta1.InferenceServicesConfig, + client client.Client) (*gatewayapiv1.HTTPRoute, error) { + var httpRouteRules []gatewayapiv1.HTTPRouteRule + var allowedHosts []gatewayapiv1.Hostname + + if !isvc.Status.IsConditionReady(v1beta1.ExplainerReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Explainer ingress not created", + }) + return nil, nil + } + + existing := &corev1.Service{} + explainerName := constants.ExplainerServiceName(isvc.Name) + + // Check if existing explainer service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultExplainerServiceName(isvc.Name), Namespace: isvc.Namespace}, existing) + if err == nil { + // Found existing explainer service with default suffix + explainerName = constants.DefaultExplainerServiceName(isvc.Name) + } + + // Add isvc name and namespace headers + filters := []gatewayapiv1.HTTPRouteFilter{addIsvcHeaders(isvc.Name, isvc.Namespace)} + + explainerHost, err := GenerateDomainName(explainerName, isvc.ObjectMeta, ingressConfig) + if err != nil { + return nil, fmt.Errorf("failed to generate explainer ingress host: %w", err) + } + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(explainerHost)) + + // Add explainer host rules + routeMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.FallbackPrefix())} + timeout := DefaultTimeout + if isvc.Spec.Explainer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Explainer.TimeoutSeconds) + } + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(routeMatch, filters, explainerName, isvc.Namespace, + constants.CommonDefaultHttpPort, timeout)) + + annotations := utils.Filter(isvc.Annotations, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) + }) + labels := utils.Filter(isvc.Labels, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceLabelDisallowedList, key) + }) + gatewaySlice := strings.Split(ingressConfig.KserveIngressGateway, "/") + httpRoute := gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.ExplainerServiceName(isvc.Name), + Namespace: isvc.Namespace, + Annotations: annotations, + Labels: labels, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: allowedHosts, + Rules: httpRouteRules, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(&gatewaySlice[0]), + Name: gatewayapiv1.ObjectName(gatewaySlice[1]), + }, + }, + }, + }, + } + return &httpRoute, nil +} + +func createRawTopLevelHTTPRoute(isvc *v1beta1.InferenceService, ingressConfig *v1beta1.IngressConfig, isvcConfig *v1beta1.InferenceServicesConfig, + client client.Client) (*gatewayapiv1.HTTPRoute, error) { + var httpRouteRules []gatewayapiv1.HTTPRouteRule + var allowedHosts []gatewayapiv1.Hostname + additionalHosts := ingressConfig.AdditionalIngressDomains + + if !isvc.Status.IsConditionReady(v1beta1.PredictorReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Predictor ingress not created", + }) + return nil, nil + } + existing := &corev1.Service{} + predictorName := constants.PredictorServiceName(isvc.Name) + transformerName := constants.TransformerServiceName(isvc.Name) + explainerName := constants.ExplainerServiceName(isvc.Name) + // Check if existing predictor service name has default suffix + err := client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultPredictorServiceName(isvc.Name), Namespace: isvc.Namespace}, existing) + if err == nil { + // Found existing predictor service with default suffix + predictorName = constants.DefaultPredictorServiceName(isvc.Name) + transformerName = constants.DefaultTransformerServiceName(isvc.Name) + explainerName = constants.DefaultExplainerServiceName(isvc.Name) + } + topLevelHost, err := GenerateDomainName(isvc.Name, isvc.ObjectMeta, ingressConfig) + if err != nil { + return nil, fmt.Errorf("failed to generate top level ingress host: %w", err) + } + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(topLevelHost)) + // Add additional hosts to allowed hosts + if additionalHosts != nil { + hostMap := make(map[string]bool, len(*additionalHosts)) + for _, host := range *additionalHosts { + hostMap[host] = true + } + for additionalHost := range hostMap { + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(additionalHost)) + } + } + // Add isvc name and namespace headers + filters := []gatewayapiv1.HTTPRouteFilter{addIsvcHeaders(isvc.Name, isvc.Namespace)} + + if isvc.Spec.Explainer != nil { + // Scenario: When explainer present + if !isvc.Status.IsConditionReady(v1beta1.ExplainerReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Explainer ingress not created", + }) + return nil, nil + } + timeout := DefaultTimeout + if isvc.Spec.Explainer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Explainer.TimeoutSeconds) + } + // Add toplevel host :explain route + // :explain routes to the explainer when there is only explainer + explainRouteMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.ExplainPrefix())} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(explainRouteMatch, filters, + explainerName, isvc.Namespace, constants.CommonDefaultHttpPort, timeout)) + } + if isvc.Spec.Transformer != nil { + // Scenario: When predictor with transformer and with/without explainer present + if !isvc.Status.IsConditionReady(v1beta1.TransformerReady) { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: "Transformer ingress not created", + }) + return nil, nil + } + timeout := DefaultTimeout + if isvc.Spec.Transformer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Transformer.TimeoutSeconds) + } + // :predict routes to the transformer when there are both predictor and transformer + routeMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.FallbackPrefix())} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(routeMatch, filters, transformerName, isvc.Namespace, constants.CommonDefaultHttpPort, timeout)) + } else { + // Scenario: When predictor without transformer and with/without explainer present + timeout := DefaultTimeout + if isvc.Spec.Predictor.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Predictor.TimeoutSeconds) + } + // Add toplevel host rules for predictor which routes all traffic to predictor + routeMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(constants.FallbackPrefix())} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(routeMatch, filters, predictorName, isvc.Namespace, constants.CommonDefaultHttpPort, timeout)) + } + + // Add path based routing rules + if ingressConfig.PathTemplate != "" { + path, err := GenerateUrlPath(isvc.Name, isvc.Namespace, ingressConfig) + if err != nil { + log.Error(err, "Failed to generate URL from pathTemplate") + return nil, fmt.Errorf("failed to generate URL from pathTemplate: %w", err) + } + path = strings.TrimSuffix(path, "/") // remove trailing "/" if present + // Include ingressDomain to the allowed hosts + allowedHosts = append(allowedHosts, gatewayapiv1.Hostname(ingressConfig.IngressDomain)) + + if isvc.Spec.Explainer != nil { + timeout := DefaultTimeout + if isvc.Spec.Explainer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Explainer.TimeoutSeconds) + } + // Add path based routing rule for :explain endpoint + explainerPathRouteMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(path + constants.PathBasedExplainPrefix())} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(explainerPathRouteMatch, filters, explainerName, isvc.Namespace, + constants.CommonDefaultHttpPort, timeout)) + } + // Add path based routing rule for :predict endpoint + if isvc.Spec.Transformer != nil { + timeout := DefaultTimeout + if isvc.Spec.Transformer.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Transformer.TimeoutSeconds) + } + // :predict routes to the transformer when there are both predictor and transformer + pathRouteMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(path + "/")} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(pathRouteMatch, filters, transformerName, isvc.Namespace, + constants.CommonDefaultHttpPort, timeout)) + } else { + timeout := DefaultTimeout + if isvc.Spec.Predictor.TimeoutSeconds != nil { + timeout = toGatewayAPIDuration(*isvc.Spec.Predictor.TimeoutSeconds) + } + // :predict routes to the predictor when there is only predictor + pathRouteMatch := []gatewayapiv1.HTTPRouteMatch{createHTTPRouteMatch(path + "/")} + httpRouteRules = append(httpRouteRules, createHTTPRouteRule(pathRouteMatch, filters, predictorName, isvc.Namespace, + constants.CommonDefaultHttpPort, timeout)) + } + } + + annotations := utils.Filter(isvc.Annotations, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) + }) + labels := utils.Filter(isvc.Labels, func(key string) bool { + return !utils.Includes(isvcConfig.ServiceLabelDisallowedList, key) + }) + gatewaySlice := strings.Split(ingressConfig.KserveIngressGateway, "/") + httpRoute := gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: isvc.Name, + Namespace: isvc.Namespace, + Annotations: annotations, + Labels: labels, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: allowedHosts, + Rules: httpRouteRules, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(&gatewaySlice[0]), + Name: gatewayapiv1.ObjectName(gatewaySlice[1]), + }, + }, + }, + }, + } + return &httpRoute, nil +} + +func semanticHttpRouteEquals(desired, existing *gatewayapiv1.HTTPRoute) bool { + return equality.Semantic.DeepEqual(desired.Spec, existing.Spec) +} + +// isHTTPRouteReady checks if the HTTPRoute is ready. If not, returns the reason and message. +func isHTTPRouteReady(httpRouteStatus gatewayapiv1.HTTPRouteStatus) (bool, *string, *string) { + if len(httpRouteStatus.Parents) == 0 { + return false, utils.ToPointer(HTTPRouteParentStatusNotAvailable), utils.ToPointer(HTTPRouteNotReady) + } + for _, parent := range httpRouteStatus.Parents { + for _, condition := range parent.Conditions { + if condition.Status == metav1.ConditionFalse { + return false, &condition.Reason, &condition.Message + } + } + } + return true, nil, nil +} + +func (r *RawHTTPRouteReconciler) reconcilePredictorHTTPRoute(ctx context.Context, isvc *v1beta1.InferenceService) error { + desired, err := createRawPredictorHTTPRoute(isvc, r.ingressConfig, r.isvcConfig, r.client) + if err != nil { + return err + } + if desired == nil { + return nil + } + if err := controllerutil.SetControllerReference(isvc, desired, r.scheme); err != nil { + log.Error(err, "Failed to set controller reference for predictor HttpRoute", "name", desired.Name) + } + existing := &gatewayapiv1.HTTPRoute{} + err = r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: isvc.Namespace}, existing) + if err != nil { + if apierr.IsNotFound(err) { + log.Info("Creating Predictor HttpRoute resource", "name", desired.Name) + if err := r.client.Create(ctx, desired); err != nil { + log.Error(err, "Failed to create predictor HttpRoute", "name", desired.Name) + return err + } + } else { + return err + } + } else { + // Set ResourceVersion which is required for update operation. + desired.ResourceVersion = existing.ResourceVersion + // Do a dry-run update to avoid diffs generated by default values. + // This will populate our local httpRoute with any default values that are present on the remote version. + if err := r.client.Update(ctx, desired, client.DryRunAll); err != nil { + log.Error(err, "Failed to perform dry-run update for predictor HttpRoute", "name", desired.Name) + return err + } + if !semanticHttpRouteEquals(desired, existing) { + if err := r.client.Update(ctx, desired); err != nil { + log.Error(err, "Failed to update predictor HttpRoute", "name", desired.Name) + } + } + } + return nil +} + +func (r *RawHTTPRouteReconciler) reconcileTransformerHTTPRoute(ctx context.Context, isvc *v1beta1.InferenceService) error { + desired, err := createRawTransformerHTTPRoute(isvc, r.ingressConfig, r.isvcConfig, r.client) + if err != nil { + return err + } + if desired == nil { + return nil + } + if err := controllerutil.SetControllerReference(isvc, desired, r.scheme); err != nil { + log.Error(err, "Failed to set controller reference for transformer HttpRoute", "name", desired.Name) + } + existing := &gatewayapiv1.HTTPRoute{} + err = r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: isvc.Namespace}, existing) + if err != nil { + if apierr.IsNotFound(err) { + log.Info("Creating transformer HttpRoute resource", "name", desired.Name) + if err := r.client.Create(ctx, desired); err != nil { + log.Error(err, "Failed to create transformer HttpRoute", "name", desired.Name) + return err + } + } else { + return err + } + } else { + // Set ResourceVersion which is required for update operation. + desired.ResourceVersion = existing.ResourceVersion + // Do a dry-run update to avoid diffs generated by default values. + // This will populate our local httpRoute with any default values that are present on the remote version. + if err := r.client.Update(ctx, desired, client.DryRunAll); err != nil { + log.Error(err, "Failed to perform dry-run update for transformer HttpRoute", "name", desired.Name) + return err + } + if !semanticHttpRouteEquals(desired, existing) { + if err := r.client.Update(ctx, desired); err != nil { + log.Error(err, "Failed to update transformer HttpRoute", "name", desired.Name) + } + } + } + return nil +} + +func (r *RawHTTPRouteReconciler) reconcileExplainerHTTPRoute(ctx context.Context, isvc *v1beta1.InferenceService) error { + desired, err := createRawExplainerHTTPRoute(isvc, r.ingressConfig, r.isvcConfig, r.client) + if err != nil { + return err + } + if desired == nil { + return nil + } + if err := controllerutil.SetControllerReference(isvc, desired, r.scheme); err != nil { + log.Error(err, "Failed to set controller reference for explainer HttpRoute", "name", desired.Name) + } + existing := &gatewayapiv1.HTTPRoute{} + err = r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: isvc.Namespace}, existing) + if err != nil { + if apierr.IsNotFound(err) { + log.Info("Creating explainer HttpRoute resource", "name", desired.Name) + if err := r.client.Create(ctx, desired); err != nil { + log.Error(err, "Failed to create explainer HttpRoute", "name", desired.Name) + return err + } + } else { + return err + } + } else { + // Set ResourceVersion which is required for update operation. + desired.ResourceVersion = existing.ResourceVersion + // Do a dry-run update to avoid diffs generated by default values. + // This will populate our local httpRoute with any default values that are present on the remote version. + if err := r.client.Update(ctx, desired, client.DryRunAll); err != nil { + log.Error(err, "Failed to perform dry-run update for explainer HttpRoute", "name", desired.Name) + return err + } + if !semanticHttpRouteEquals(desired, existing) { + if err := r.client.Update(ctx, desired); err != nil { + log.Error(err, "Failed to update explainer HttpRoute", "name", desired.Name) + } + } + } + return nil +} + +func (r *RawHTTPRouteReconciler) reconcileTopLevelHTTPRoute(ctx context.Context, isvc *v1beta1.InferenceService) error { + desired, err := createRawTopLevelHTTPRoute(isvc, r.ingressConfig, r.isvcConfig, r.client) + if err != nil { + return err + } + if desired == nil { + return nil + } + if err := controllerutil.SetControllerReference(isvc, desired, r.scheme); err != nil { + log.Error(err, "Failed to set controller reference for top level HttpRoute", "name", isvc.Name) + return err + } + // reconcile httpRoute + existingHttpRoute := &gatewayapiv1.HTTPRoute{} + err = r.client.Get(ctx, types.NamespacedName{ + Namespace: isvc.Namespace, + Name: isvc.Name, + }, existingHttpRoute) + if err != nil { + if apierr.IsNotFound(err) { + log.Info("Creating top level HttpRoute resource", "name", isvc.Name) + if err := r.client.Create(ctx, desired); err != nil { + log.Error(err, "Failed to create top level HttpRoute", "name", desired.Name) + return err + } + } else { + return err + } + } else { + // Set ResourceVersion which is required for update operation. + desired.ResourceVersion = existingHttpRoute.ResourceVersion + // Do a dry-run update to avoid diffs generated by default values. + // This will populate our local httpRoute with any default values that are present on the remote version. + if err := r.client.Update(ctx, desired, client.DryRunAll); err != nil { + log.Error(err, "Failed to perform dry-run update on top level httpRoute", "name", desired.Name) + return err + } + if !semanticHttpRouteEquals(desired, existingHttpRoute) { + if err = r.client.Update(ctx, desired); err != nil { + log.Error(err, "Failed to update toplevel HttpRoute", "name", isvc.Name) + return err + } + } + } + return nil +} + +// ReconcileHTTPRoute reconciles the HTTPRoute resource +func (r *RawHTTPRouteReconciler) Reconcile(ctx context.Context, isvc *v1beta1.InferenceService) error { + var err error + isInternal := false + // disable ingress creation if service is labelled with cluster local or kserve domain is cluster local + if val, ok := isvc.Labels[constants.NetworkVisibility]; ok && val == constants.ClusterLocalVisibility { + isInternal = true + } + if r.ingressConfig.IngressDomain == constants.ClusterLocalDomain { + isInternal = true + } + if !isInternal && !r.ingressConfig.DisableIngressCreation { + if err := r.reconcilePredictorHTTPRoute(ctx, isvc); err != nil { + return err + } + if isvc.Spec.Transformer != nil { + if err := r.reconcileTransformerHTTPRoute(ctx, isvc); err != nil { + return err + } + } + if isvc.Spec.Explainer != nil { + if err := r.reconcileExplainerHTTPRoute(ctx, isvc); err != nil { + return err + } + } + if err := r.reconcileTopLevelHTTPRoute(ctx, isvc); err != nil { + return err + } + + // Check Predictor HTTPRoute status + httpRoute := &gatewayapiv1.HTTPRoute{} + if err := r.client.Get(ctx, types.NamespacedName{ + Name: constants.PredictorServiceName(isvc.Name), + Namespace: isvc.Namespace}, httpRoute); err != nil { + return err + } + if ready, reason, message := isHTTPRouteReady(httpRoute.Status); !ready { + log.Info("Predictor HTTPRoute not ready", "reason", *reason, "message", *message) + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: *reason, + Message: fmt.Sprintf("%s %s", "Predictor", *message), + }) + return nil + } + // Check Transformer HTTPRoute stauts + if isvc.Spec.Transformer != nil { + httpRoute = &gatewayapiv1.HTTPRoute{} + if err := r.client.Get(ctx, types.NamespacedName{ + Name: constants.TransformerServiceName(isvc.Name), + Namespace: isvc.Namespace}, httpRoute); err != nil { + return err + } + if ready, reason, message := isHTTPRouteReady(httpRoute.Status); !ready { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: *reason, + Message: fmt.Sprintf("%s %s", "Transformer", *message), + }) + return nil + } + } + // Check Explainer HTTPRoute stauts + if isvc.Spec.Explainer != nil { + httpRoute = &gatewayapiv1.HTTPRoute{} + if err := r.client.Get(ctx, types.NamespacedName{ + Name: constants.ExplainerServiceName(isvc.Name), + Namespace: isvc.Namespace}, httpRoute); err != nil { + return err + } + if ready, reason, message := isHTTPRouteReady(httpRoute.Status); !ready { + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: *reason, + Message: fmt.Sprintf("%s %s", "Explainer", *message), + }) + return nil + } + } + // Check Top level HTTPRoute status + httpRoute = &gatewayapiv1.HTTPRoute{} + if err := r.client.Get(ctx, types.NamespacedName{ + Name: isvc.Name, + Namespace: isvc.Namespace}, httpRoute); err != nil { + return err + } + if ready, reason, message := isHTTPRouteReady(httpRoute.Status); !ready { + log.Info("Top level HTTPRoute not ready", "reason", *reason, "message", *message) + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionFalse, + Reason: *reason, + Message: fmt.Sprintf("%s %s", "TopLevel", *message), + }) + return nil + } + // If we are here, then all the HTTPRoutes are ready, Mark ingress as ready + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionTrue, + }) + } else { + // Ingress creation is disabled. We set it to true as the isvc condition depends on it. + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionTrue, + }) + } + isvc.Status.URL, err = createRawURL(isvc, r.ingressConfig) + if err != nil { + return err + } + isvc.Status.Address = &duckv1.Addressable{ + URL: &apis.URL{ + Host: getRawServiceHost(isvc, r.client), + Scheme: r.ingressConfig.UrlScheme, + Path: "", + }, + } + return nil +} diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler_test.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler_test.go new file mode 100644 index 00000000000..fca475856ad --- /dev/null +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/httproute_reconciler_test.go @@ -0,0 +1,2088 @@ +/* +Copyright 2024 The KServe Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ingress + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp/cmpopts" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/scheme" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + v1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1" + "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" +) + +func TestCreateRawURL(t *testing.T) { + g := NewGomegaWithT(t) + + testCases := map[string]struct { + isvc *v1beta1.InferenceService + ingressConfig *v1beta1.IngressConfig + expectedURL string + isErrorExpected bool + }{ + "basic case": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + }, + isErrorExpected: false, + expectedURL: "http://test-isvc-default.example.com", + }, + "basic case with empty domain template": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "", + }, + expectedURL: "", + isErrorExpected: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + url, err := createRawURL(tc.isvc, tc.ingressConfig) + if tc.isErrorExpected { + g.Expect(err).ToNot(BeNil()) + } else { + g.Expect(err).To(BeNil()) + } + g.Expect(tc.expectedURL).To(BeComparableTo(url.String())) + }) + } +} + +func TestGetRawServiceHost(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvc *v1beta1.InferenceService + expectedHost string + }{ + "basic case": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + }, + expectedHost: "test-isvc-predictor.default.svc.cluster.local", + }, + "basic case with transformer": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + }, + expectedHost: "test-isvc-transformer.default.svc.cluster.local", + }, + "predictor with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-pred-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + }, + expectedHost: "test-isvc-pred-default-predictor.default.svc.cluster.local", + }, + "transformer with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-pred-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + }, + expectedHost: "test-isvc-pred-default-transformer.default.svc.cluster.local", + }, + } + + s := scheme.Scheme + s.AddKnownTypes(v1beta1.SchemeGroupVersion, &v1beta1.InferenceService{}) + client := fake.NewClientBuilder().WithScheme(s).Build() + // Create a dummy service to test default suffix cases + client.Create(context.Background(), &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-pred-default", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{}, + }) + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + host := getRawServiceHost(tc.isvc, client) + g.Expect(tc.expectedHost).To(BeComparableTo(host)) + }) + } +} + +func TestCreateHTTPRouteMatch(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + prefix string + expectedHTTPRoutes gatewayapiv1.HTTPRouteMatch + }{ + "basic case": { + prefix: "^.*$", + expectedHTTPRoutes: gatewayapiv1.HTTPRouteMatch{ + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^.*$"), + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + matches := createHTTPRouteMatch(tc.prefix) + g.Expect(matches).To(BeComparableTo(tc.expectedHTTPRoutes)) + }) + } +} + +func TestAddIsvcHeaders(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvcName string + isvcNamespace string + }{ + "basic case": { + isvcName: "test-isvc", + isvcNamespace: "default", + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + headers := addIsvcHeaders(tc.isvcName, tc.isvcNamespace) + g.Expect(headers.Type).To(BeComparableTo(gatewayapiv1.HTTPRouteFilterRequestHeaderModifier)) + g.Expect(headers.RequestHeaderModifier.Set).To(HaveLen(2)) + g.Expect(string(headers.RequestHeaderModifier.Set[0].Name)).To(BeComparableTo(constants.IsvcNameHeader)) + g.Expect(headers.RequestHeaderModifier.Set[0].Value).To(BeComparableTo(tc.isvcName)) + g.Expect(string(headers.RequestHeaderModifier.Set[1].Name)).To(BeComparableTo(constants.IsvcNamespaceHeader)) + g.Expect(headers.RequestHeaderModifier.Set[1].Value).To(BeComparableTo(tc.isvcNamespace)) + }) + } +} + +func TestCreateHTTPRouteRule(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + matches []gatewayapiv1.HTTPRouteMatch + filters []gatewayapiv1.HTTPRouteFilter + serviceName string + servicePort int32 + expectedRules int + }{ + "basic case": { + matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("/predict"), + }, + }, + }, + filters: []gatewayapiv1.HTTPRouteFilter{ + addIsvcHeaders("test-isvc", "default"), + }, + serviceName: "test-service", + servicePort: 80, + expectedRules: 1, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + rule := createHTTPRouteRule(tc.matches, tc.filters, tc.serviceName, "default", tc.servicePort, DefaultTimeout) + g.Expect(rule.Matches).To(HaveLen(tc.expectedRules)) + g.Expect(rule.Filters).To(HaveLen(tc.expectedRules)) + g.Expect(rule.BackendRefs).To(HaveLen(tc.expectedRules)) + g.Expect(string(rule.BackendRefs[0].Name)).To(BeComparableTo(tc.serviceName)) + }) + } +} + +func TestSemanticHttpRouteEquals(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + desired *gatewayapiv1.HTTPRoute + existing *gatewayapiv1.HTTPRoute + expectedEqual bool + }{ + "equal routes": { + desired: &gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"example.com"}, + }, + }, + existing: &gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"example.com"}, + }, + }, + expectedEqual: true, + }, + "different routes": { + desired: &gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"example.com"}, + }, + }, + existing: &gatewayapiv1.HTTPRoute{ + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"different.com"}, + }, + }, + expectedEqual: false, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + g.Expect(semanticHttpRouteEquals(tc.desired, tc.existing)).To(BeComparableTo(tc.expectedEqual)) + }) + } +} + +func TestIsHTTPRouteReady(t *testing.T) { + g := NewGomegaWithT(t) + testCases := map[string]struct { + httpRouteStatus gatewayapiv1.HTTPRouteStatus + expectedReady bool + expectedReason *string + expectedMessage *string + }{ + "route accepted": { + httpRouteStatus: gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + }, + { + Type: string(gatewayapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + }, + }, + }, + }, + }, + }, + expectedReady: true, + expectedReason: nil, + expectedMessage: nil, + }, + "route not accepted": { + httpRouteStatus: gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{ + { + Conditions: []metav1.Condition{ + { + Type: string(gatewayapiv1.RouteConditionAccepted), + Status: metav1.ConditionFalse, + Reason: "Route not accepted", + Message: "Route not accepted", + }, + { + Type: string(gatewayapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + }, + }, + }, + }, + }, + }, + expectedReady: false, + expectedReason: utils.ToPointer("Route not accepted"), + expectedMessage: utils.ToPointer("Route not accepted"), + }, + "no parent status": { + httpRouteStatus: gatewayapiv1.HTTPRouteStatus{ + RouteStatus: gatewayapiv1.RouteStatus{ + Parents: []gatewayapiv1.RouteParentStatus{}, + }, + }, + expectedReady: false, + expectedReason: utils.ToPointer(HTTPRouteParentStatusNotAvailable), + expectedMessage: utils.ToPointer(HTTPRouteNotReady), + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + ready, reason, message := isHTTPRouteReady(tc.httpRouteStatus) + g.Expect(ready).To(BeComparableTo(tc.expectedReady)) + g.Expect(reason).To(BeComparableTo(tc.expectedReason)) + g.Expect(message).To(BeComparableTo(tc.expectedMessage)) + }) + } +} + +func TestCreateRawTopLevelHTTPRoute(t *testing.T) { + format.MaxLength = 0 + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvc *v1beta1.InferenceService + ingressConfig *v1beta1.IngressConfig + expected *gatewayapiv1.HTTPRoute + }{ + "Predictor ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default.example.com", "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-predictor", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + "When predictor not ready, httproute should not be created": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionFalse, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: nil, + }, + "With transformer ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionTrue, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default.example.com", "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-transformer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + "When transformer not ready, httproute should not be created": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionFalse, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: nil, + }, + "With explainer ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionTrue, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default.example.com", "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.ExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-explainer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-predictor", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + "When explainer not ready, httproute should not be created": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionFalse, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: nil, + }, + "Path based routing with explainer": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionTrue, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + PathTemplate: "/serving/{{ .Namespace }}/{{ .Name }}", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default.example.com", "additional.example.com", "example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer(constants.ExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-explainer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-predictor", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("/serving/default/test-isvc" + constants.PathBasedExplainPrefix()), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-explainer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("/serving/default/test-isvc/"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-predictor", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + "Path based routing with transformer": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionTrue, + }, + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + PathTemplate: "/serving/{{ .Namespace }}/{{ .Name }}", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default.example.com", "additional.example.com", "example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-transformer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("/serving/default/test-isvc/"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-transformer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + "Predictor with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + AdditionalIngressDomains: &[]string{"additional.example.com"}, + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default-default.example.com", "additional.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc-default", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-default-predictor-default", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "kserve-gateway", + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.GatewayKind)), + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Namespace: utils.ToPointer(gatewayapiv1.Namespace("kserve")), + }, + }, + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + s := scheme.Scheme + s.AddKnownTypes(v1beta1.SchemeGroupVersion, &v1beta1.InferenceService{}) + s.AddKnownTypes(schema.GroupVersion{Group: gatewayapiv1.GroupVersion.Group, Version: gatewayapiv1.GroupVersion.Version}, + &gatewayapiv1.HTTPRoute{}) + client := fake.NewClientBuilder().WithScheme(s).Build() + // Create a dummy service to test default suffix case + client.Create(context.Background(), &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-predictor-default", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{}}) + isvcConfig := &v1beta1.InferenceServicesConfig{ + ServiceAnnotationDisallowedList: []string{}, + ServiceLabelDisallowedList: []string{}, + } + httpRoute, err := createRawTopLevelHTTPRoute(tc.isvc, tc.ingressConfig, isvcConfig, client) + + g.Expect(err).To(BeNil()) + if tc.expected != nil { + g.Expect(httpRoute.Spec).To(BeComparableTo(tc.expected.Spec)) + g.Expect(httpRoute.ObjectMeta).To(BeComparableTo(tc.expected.ObjectMeta, cmpopts.IgnoreFields(httpRoute.ObjectMeta, "CreationTimestamp"))) + } else { + g.Expect(httpRoute).To(BeNil()) + } + }) + } +} + +func TestCreateRawPredictorHTTPRoute(t *testing.T) { + format.MaxLength = 0 + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvc *v1beta1.InferenceService + ingressConfig *v1beta1.IngressConfig + expected *gatewayapiv1.HTTPRoute + }{ + "Predictor ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-predictor", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-predictor-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-predictor", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + "Predictor not ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionFalse, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: nil, + }, + "Predictor with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.PredictorReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-predictor", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default-predictor-default-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc-default", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-default-predictor-default", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + s := scheme.Scheme + s.AddKnownTypes(v1beta1.SchemeGroupVersion, &v1beta1.InferenceService{}) + s.AddKnownTypes(schema.GroupVersion{Group: gatewayapiv1.GroupVersion.Group, Version: gatewayapiv1.GroupVersion.Version}, + &gatewayapiv1.HTTPRoute{}) + client := fake.NewClientBuilder().WithScheme(s).Build() + // Create a dummy service to test default suffix case + client.Create(context.Background(), &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-predictor-default", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{}}) + isvcConfig := &v1beta1.InferenceServicesConfig{ + ServiceAnnotationDisallowedList: []string{}, + ServiceLabelDisallowedList: []string{}, + } + httpRoute, err := createRawPredictorHTTPRoute(tc.isvc, tc.ingressConfig, isvcConfig, client) + + g.Expect(err).To(BeNil()) + if tc.expected != nil { + g.Expect(httpRoute.Spec).To(BeComparableTo(tc.expected.Spec)) + g.Expect(httpRoute.ObjectMeta).To(BeComparableTo(tc.expected.ObjectMeta, cmpopts.IgnoreFields(httpRoute.ObjectMeta, "CreationTimestamp"))) + } else { + g.Expect(httpRoute).To(BeNil()) + } + }) + } +} + +func TestCreateRawTransformerHTTPRoute(t *testing.T) { + format.MaxLength = 0 + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvc *v1beta1.InferenceService + ingressConfig *v1beta1.IngressConfig + expected *gatewayapiv1.HTTPRoute + }{ + "Transformer ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-transformer", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-transformer-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-transformer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + "Transformer not ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionFalse, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: nil, + }, + "Transformer with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Transformer: &v1beta1.TransformerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.TransformerReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-transformer", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default-transformer-default-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc-default", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-default-transformer-default", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + s := scheme.Scheme + s.AddKnownTypes(v1beta1.SchemeGroupVersion, &v1beta1.InferenceService{}) + s.AddKnownTypes(schema.GroupVersion{Group: gatewayapiv1.GroupVersion.Group, Version: gatewayapiv1.GroupVersion.Version}, + &gatewayapiv1.HTTPRoute{}) + client := fake.NewClientBuilder().WithScheme(s).Build() + // Create a dummy service to test default suffix case + client.Create(context.Background(), &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-transformer-default", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{}}) + isvcConfig := &v1beta1.InferenceServicesConfig{ + ServiceAnnotationDisallowedList: []string{}, + ServiceLabelDisallowedList: []string{}, + } + httpRoute, err := createRawTransformerHTTPRoute(tc.isvc, tc.ingressConfig, isvcConfig, client) + + g.Expect(err).To(BeNil()) + if tc.expected != nil { + g.Expect(httpRoute.Spec).To(BeComparableTo(tc.expected.Spec)) + g.Expect(httpRoute.ObjectMeta).To(BeComparableTo(tc.expected.ObjectMeta, cmpopts.IgnoreFields(httpRoute.ObjectMeta, "CreationTimestamp"))) + } else { + g.Expect(httpRoute).To(BeNil()) + } + }) + } +} + +func TestCreateRawExplainerHTTPRoute(t *testing.T) { + format.MaxLength = 0 + g := NewGomegaWithT(t) + testCases := map[string]struct { + isvc *v1beta1.InferenceService + ingressConfig *v1beta1.IngressConfig + expected *gatewayapiv1.HTTPRoute + }{ + "Explainer ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-explainer", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-explainer-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-explainer", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + "Explainer not ready": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionFalse, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: nil, + }, + "Explainer with default suffix": { + isvc: &v1beta1.InferenceService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default", + Namespace: "default", + }, + Spec: v1beta1.InferenceServiceSpec{ + Predictor: v1beta1.PredictorSpec{}, + Explainer: &v1beta1.ExplainerSpec{}, + }, + Status: v1beta1.InferenceServiceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: v1beta1.ExplainerReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + ingressConfig: &v1beta1.IngressConfig{ + IngressDomain: "example.com", + UrlScheme: "http", + DomainTemplate: "{{.Name}}-{{.Namespace}}.{{.IngressDomain}}", + KserveIngressGateway: "kserve/kserve-gateway", + EnableGatewayAPI: true, + }, + expected: &gatewayapiv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-explainer", + Namespace: "default", + Annotations: map[string]string{}, + Labels: map[string]string{}, + }, + Spec: gatewayapiv1.HTTPRouteSpec{ + Hostnames: []gatewayapiv1.Hostname{"test-isvc-default-explainer-default-default.example.com"}, + Rules: []gatewayapiv1.HTTPRouteRule{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: utils.ToPointer(gatewayapiv1.PathMatchRegularExpression), + Value: utils.ToPointer("^/.*$"), + }, + }, + }, + Filters: []gatewayapiv1.HTTPRouteFilter{ + { + Type: gatewayapiv1.HTTPRouteFilterRequestHeaderModifier, + RequestHeaderModifier: &gatewayapiv1.HTTPHeaderFilter{ + Set: []gatewayapiv1.HTTPHeader{ + { + Name: constants.IsvcNameHeader, + Value: "test-isvc-default", + }, + { + Name: constants.IsvcNamespaceHeader, + Value: "default", + }, + }, + }, + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Kind: utils.ToPointer(gatewayapiv1.Kind(constants.ServiceKind)), + Name: "test-isvc-default-explainer-default", + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("default")), + Port: (*gatewayapiv1.PortNumber)(utils.ToPointer(int32(constants.CommonDefaultHttpPort))), + }, + }, + }, + }, + Timeouts: &gatewayapiv1.HTTPRouteTimeouts{ + Request: utils.ToPointer(gatewayapiv1.Duration("60s")), + }, + }, + }, + CommonRouteSpec: gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Group: (*gatewayapiv1.Group)(&gatewayapiv1.GroupVersion.Group), + Kind: (*gatewayapiv1.Kind)(utils.ToPointer(constants.GatewayKind)), + Namespace: (*gatewayapiv1.Namespace)(utils.ToPointer("kserve")), + Name: gatewayapiv1.ObjectName("kserve-gateway"), + }, + }, + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + s := scheme.Scheme + s.AddKnownTypes(v1beta1.SchemeGroupVersion, &v1beta1.InferenceService{}) + s.AddKnownTypes(schema.GroupVersion{Group: gatewayapiv1.GroupVersion.Group, Version: gatewayapiv1.GroupVersion.Version}, + &gatewayapiv1.HTTPRoute{}) + client := fake.NewClientBuilder().WithScheme(s).Build() + // Create a dummy service to test default suffix case + client.Create(context.Background(), &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-isvc-default-explainer-default", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{}}) + isvcConfig := &v1beta1.InferenceServicesConfig{ + ServiceAnnotationDisallowedList: []string{}, + ServiceLabelDisallowedList: []string{}, + } + httpRoute, err := createRawExplainerHTTPRoute(tc.isvc, tc.ingressConfig, isvcConfig, client) + + g.Expect(err).To(BeNil()) + if tc.expected != nil { + g.Expect(httpRoute.Spec).To(BeComparableTo(tc.expected.Spec)) + g.Expect(httpRoute.ObjectMeta).To(BeComparableTo(tc.expected.ObjectMeta, cmpopts.IgnoreFields(httpRoute.ObjectMeta, "CreationTimestamp"))) + } else { + g.Expect(httpRoute).To(BeNil()) + } + }) + } +} diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler.go index 702659d73b5..b924292adf8 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler.go @@ -22,6 +22,9 @@ import ( "os" "strings" + duckv1 "knative.dev/pkg/apis/duck/v1" + knservingv1 "knative.dev/serving/pkg/apis/serving/v1" + "github.com/google/go-cmp/cmp" "github.com/pkg/errors" "google.golang.org/protobuf/testing/protocmp" @@ -36,11 +39,9 @@ import ( "k8s.io/apimachinery/pkg/util/validation" "k8s.io/client-go/kubernetes" "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmp" "knative.dev/pkg/network" "knative.dev/pkg/system" - knservingv1 "knative.dev/serving/pkg/apis/serving/v1" "knative.dev/serving/pkg/reconciler/route/config" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -62,14 +63,103 @@ type IngressReconciler struct { clientset kubernetes.Interface scheme *runtime.Scheme ingressConfig *v1beta1.IngressConfig + isvcConfig *v1beta1.InferenceServicesConfig } -func NewIngressReconciler(client client.Client, clientset kubernetes.Interface, scheme *runtime.Scheme, ingressConfig *v1beta1.IngressConfig) *IngressReconciler { +func NewIngressReconciler(client client.Client, clientset kubernetes.Interface, scheme *runtime.Scheme, + ingressConfig *v1beta1.IngressConfig, isvcConfig *v1beta1.InferenceServicesConfig) *IngressReconciler { return &IngressReconciler{ client: client, clientset: clientset, scheme: scheme, ingressConfig: ingressConfig, + isvcConfig: isvcConfig, + } +} + +func (ir *IngressReconciler) Reconcile(isvc *v1beta1.InferenceService) error { + serviceHost := getServiceHost(isvc) + serviceUrl := getServiceUrl(isvc, ir.ingressConfig) + disableIstioVirtualHost := ir.ingressConfig.DisableIstioVirtualHost + if serviceHost == "" || serviceUrl == "" { + return nil + } + // When Istio virtual host is disabled, we return the underlying component url. + // When Istio virtual host is enabled. we return the url using inference service virtual host name and redirect to the corresponding transformer, predictor or explainer url. + if !disableIstioVirtualHost { + // Check if existing knative service name has default suffix + defaultNameExisting := &knservingv1.Service{} + useDefault := false + err := ir.client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultPredictorServiceName(isvc.Name), Namespace: isvc.Namespace}, defaultNameExisting) + if err == nil { + useDefault = true + } + domainList := getDomainList(ir.clientset) + desiredIngress := createIngress(isvc, useDefault, ir.ingressConfig, domainList, ir.isvcConfig) + if desiredIngress == nil { + return nil + } + + // Create external service which points to local gateway + if err := ir.reconcileExternalService(isvc, ir.ingressConfig); err != nil { + return errors.Wrapf(err, "fails to reconcile external name service") + } + + if err := controllerutil.SetControllerReference(isvc, desiredIngress, ir.scheme); err != nil { + return errors.Wrapf(err, "fails to set owner reference for ingress") + } + + existing := &istioclientv1beta1.VirtualService{} + err = ir.client.Get(context.TODO(), types.NamespacedName{Name: desiredIngress.Name, Namespace: desiredIngress.Namespace}, existing) + if err != nil { + if apierr.IsNotFound(err) { + log.Info("Creating Ingress for isvc", "namespace", desiredIngress.Namespace, "name", desiredIngress.Name) + err = ir.client.Create(context.TODO(), desiredIngress) + } + } else { + if !routeSemanticEquals(desiredIngress, existing) { + deepCopy := existing.DeepCopy() + deepCopy.Spec = *desiredIngress.Spec.DeepCopy() + deepCopy.Annotations = desiredIngress.Annotations + deepCopy.Labels = desiredIngress.Labels + log.Info("Update Ingress for isvc", "namespace", desiredIngress.Namespace, "name", desiredIngress.Name) + err = ir.client.Update(context.TODO(), deepCopy) + } + } + if err != nil { + return errors.Wrapf(err, "fails to create or update ingress") + } + } + + if url, err := apis.ParseURL(serviceUrl); err == nil { + isvc.Status.URL = url + var hostPrefix string + if disableIstioVirtualHost { + // Check if existing kubernetes service name has default suffix + existingServiceWithDefaultSuffix := &corev1.Service{} + useDefault := false + err := ir.client.Get(context.TODO(), types.NamespacedName{Name: constants.DefaultPredictorServiceName(isvc.Name), Namespace: isvc.Namespace}, existingServiceWithDefaultSuffix) + if err == nil { + useDefault = true + } + hostPrefix = getHostPrefix(isvc, disableIstioVirtualHost, useDefault) + } else { + hostPrefix = getHostPrefix(isvc, disableIstioVirtualHost, false) + } + + isvc.Status.Address = &duckv1.Addressable{ + URL: &apis.URL{ + Host: network.GetServiceHostname(hostPrefix, isvc.Namespace), + Scheme: "http", + }, + } + isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ + Type: v1beta1.IngressReady, + Status: corev1.ConditionTrue, + }) + return nil + } else { + return errors.Wrapf(err, "fails to parse service url") } } @@ -357,7 +447,8 @@ func gatewaysEqual(matchRequest, matchRequestDest *istiov1beta1.HTTPMatchRequest return equality.Semantic.DeepEqual(matchRequest.Gateways, matchRequestDest.Gateways) } -func createIngress(isvc *v1beta1.InferenceService, useDefault bool, config *v1beta1.IngressConfig, domainList *[]string) *istioclientv1beta1.VirtualService { +func createIngress(isvc *v1beta1.InferenceService, useDefault bool, config *v1beta1.IngressConfig, + domainList *[]string, isvcConfig *v1beta1.InferenceServicesConfig) *istioclientv1beta1.VirtualService { if !isvc.Status.IsConditionReady(v1beta1.PredictorReady) { status := corev1.ConditionFalse if isvc.Status.IsConditionUnknown(v1beta1.PredictorReady) { @@ -586,7 +677,7 @@ func createIngress(isvc *v1beta1.InferenceService, useDefault bool, config *v1be } } annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) }) desiredIngress := &istioclientv1beta1.VirtualService{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler_test.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler_test.go index afe5fa25955..63d5b9747e9 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler_test.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/ingress_reconciler_test.go @@ -70,6 +70,11 @@ func TestCreateVirtualService(t *testing.T) { Gateways: []string{constants.KnativeIngressGateway}, }, } + defaultInferenceServiceConfig := &v1beta1.InferenceServicesConfig{ + Explainers: v1beta1.ExplainersConfig{}, + ServiceAnnotationDisallowedList: constants.ServiceAnnotationDisallowedList, + ServiceLabelDisallowedList: constants.RevisionTemplateLabelDisallowedList, + } cases := []struct { name string isvc *v1beta1.InferenceService @@ -1537,7 +1542,7 @@ func TestCreateVirtualService(t *testing.T) { testIsvc.Spec.Explainer = &v1beta1.ExplainerSpec{} } - actualService := createIngress(testIsvc, tc.useDefault, tc.ingressConfig, tc.domainList) + actualService := createIngress(testIsvc, tc.useDefault, tc.ingressConfig, tc.domainList, defaultInferenceServiceConfig) if diff := cmp.Diff(tc.expectedService.DeepCopy(), actualService.DeepCopy(), protocmp.Transform()); diff != "" { t.Errorf("Test %q unexpected status (-want +got): %v", tc.name, diff) } @@ -1703,7 +1708,7 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{}, + v1beta1.PredictorComponent: {}, }, ModelStatus: v1beta1.ModelStatus{}, }, @@ -1732,7 +1737,7 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(defaultPredictorUrl), }, }, @@ -1763,10 +1768,10 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(defaultPredictorUrl), }, - v1beta1.TransformerComponent: v1beta1.ComponentStatusSpec{ + v1beta1.TransformerComponent: { URL: (*apis.URL)(defaultTransformerUrl), }, }, @@ -1819,7 +1824,7 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(defaultPredictorUrl), }, }, @@ -1850,10 +1855,10 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(defaultPredictorUrl), }, - v1beta1.TransformerComponent: v1beta1.ComponentStatusSpec{ + v1beta1.TransformerComponent: { URL: nil, }, }, @@ -1884,10 +1889,10 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(predictorUrl), }, - v1beta1.TransformerComponent: v1beta1.ComponentStatusSpec{ + v1beta1.TransformerComponent: { URL: (*apis.URL)(transformerUrl), }, }, @@ -1917,7 +1922,7 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(predictorUrl), }, }, @@ -1947,7 +1952,7 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(predictorUrl), }, }, @@ -1978,10 +1983,10 @@ func TestGetServiceUrl(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(predictorUrl), }, - v1beta1.TransformerComponent: v1beta1.ComponentStatusSpec{ + v1beta1.TransformerComponent: { URL: (*apis.URL)(transformerUrl), }, }, @@ -2053,7 +2058,7 @@ func TestGetServiceUrlPathBased(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{}, + v1beta1.PredictorComponent: {}, }, ModelStatus: v1beta1.ModelStatus{}, }, @@ -2078,7 +2083,7 @@ func TestGetServiceUrlPathBased(t *testing.T) { Address: nil, URL: nil, Components: map[v1beta1.ComponentType]v1beta1.ComponentStatusSpec{ - v1beta1.PredictorComponent: v1beta1.ComponentStatusSpec{ + v1beta1.PredictorComponent: { URL: (*apis.URL)(predictorUrl), }, }, diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/kube_ingress_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/kube_ingress_reconciler.go index 28679560f00..211df0302b9 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/kube_ingress_reconciler.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/ingress/kube_ingress_reconciler.go @@ -21,7 +21,7 @@ import ( "fmt" "strconv" - v1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1" + "github.com/kserve/kserve/pkg/apis/serving/v1beta1" "github.com/kserve/kserve/pkg/constants" v1beta1utils "github.com/kserve/kserve/pkg/controller/v1beta1/inferenceservice/utils" "github.com/kserve/kserve/pkg/utils" @@ -45,15 +45,18 @@ type RawIngressReconciler struct { client client.Client scheme *runtime.Scheme ingressConfig *v1beta1.IngressConfig + isvcConfig *v1beta1.InferenceServicesConfig } func NewRawIngressReconciler(client client.Client, scheme *runtime.Scheme, - ingressConfig *v1beta1.IngressConfig) (*RawIngressReconciler, error) { + ingressConfig *v1beta1.IngressConfig, + isvcConfig *v1beta1.InferenceServicesConfig) (*RawIngressReconciler, error) { return &RawIngressReconciler{ client: client, scheme: scheme, ingressConfig: ingressConfig, + isvcConfig: isvcConfig, }, nil } @@ -143,10 +146,11 @@ func generateRule(ingressHost string, componentName string, path string, port in } func generateMetadata(isvc *v1beta1.InferenceService, - componentType constants.InferenceServiceComponent, name string) metav1.ObjectMeta { + componentType constants.InferenceServiceComponent, name string, + isvcConfig *v1beta1.InferenceServicesConfig) metav1.ObjectMeta { // get annotations from isvc annotations := utils.Filter(isvc.Annotations, func(key string) bool { - return !utils.Includes(constants.ServiceAnnotationDisallowedList, key) + return !utils.Includes(isvcConfig.ServiceAnnotationDisallowedList, key) }) objectMeta := metav1.ObjectMeta{ Name: name, @@ -163,10 +167,11 @@ func generateMetadata(isvc *v1beta1.InferenceService, // generateIngressHost return the config domain in configmap.IngressDomain func generateIngressHost(ingressConfig *v1beta1.IngressConfig, isvc *v1beta1.InferenceService, + isvcConfig *v1beta1.InferenceServicesConfig, componentType string, topLevelFlag bool, name string) (string, error) { - metadata := generateMetadata(isvc, constants.InferenceServiceComponent(componentType), name) + metadata := generateMetadata(isvc, constants.InferenceServiceComponent(componentType), name, isvcConfig) if !topLevelFlag { return GenerateDomainName(metadata.Name, isvc.ObjectMeta, ingressConfig) } else { @@ -175,7 +180,8 @@ func generateIngressHost(ingressConfig *v1beta1.IngressConfig, } func createRawIngress(scheme *runtime.Scheme, isvc *v1beta1.InferenceService, - ingressConfig *v1beta1.IngressConfig, client client.Client) (*netv1.Ingress, error) { + ingressConfig *v1beta1.IngressConfig, client client.Client, + isvcConfig *v1beta1.InferenceServicesConfig) (*netv1.Ingress, error) { if !isvc.Status.IsConditionReady(v1beta1.PredictorReady) { isvc.Status.SetCondition(v1beta1.IngressReady, &apis.Condition{ Type: v1beta1.IngressReady, @@ -205,16 +211,16 @@ func createRawIngress(scheme *runtime.Scheme, isvc *v1beta1.InferenceService, predictorName = constants.DefaultPredictorServiceName(isvc.Name) explainerName = constants.DefaultExplainerServiceName(isvc.Name) } - host, err := generateIngressHost(ingressConfig, isvc, string(constants.Transformer), true, transformerName) + host, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Transformer), true, transformerName) if err != nil { return nil, fmt.Errorf("failed creating top level transformer ingress host: %w", err) } - transformerHost, err := generateIngressHost(ingressConfig, isvc, string(constants.Transformer), false, transformerName) + transformerHost, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Transformer), false, transformerName) if err != nil { return nil, fmt.Errorf("failed creating transformer ingress host: %w", err) } if isvc.Spec.Explainer != nil { - explainerHost, err := generateIngressHost(ingressConfig, isvc, string(constants.Explainer), false, transformerName) + explainerHost, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Explainer), false, transformerName) if err != nil { return nil, fmt.Errorf("failed creating explainer ingress host: %w", err) } @@ -238,11 +244,11 @@ func createRawIngress(scheme *runtime.Scheme, isvc *v1beta1.InferenceService, explainerName = constants.DefaultExplainerServiceName(isvc.Name) predictorName = constants.DefaultPredictorServiceName(isvc.Name) } - host, err := generateIngressHost(ingressConfig, isvc, string(constants.Explainer), true, explainerName) + host, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Explainer), true, explainerName) if err != nil { return nil, fmt.Errorf("failed creating top level explainer ingress host: %w", err) } - explainerHost, err := generateIngressHost(ingressConfig, isvc, string(constants.Explainer), false, explainerName) + explainerHost, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Explainer), false, explainerName) if err != nil { return nil, fmt.Errorf("failed creating explainer ingress host: %w", err) } @@ -254,14 +260,14 @@ func createRawIngress(scheme *runtime.Scheme, isvc *v1beta1.InferenceService, if err == nil { predictorName = constants.DefaultPredictorServiceName(isvc.Name) } - host, err := generateIngressHost(ingressConfig, isvc, string(constants.Predictor), true, predictorName) + host, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Predictor), true, predictorName) if err != nil { return nil, fmt.Errorf("failed creating top level predictor ingress host: %w", err) } rules = append(rules, generateRule(host, predictorName, "/", constants.CommonDefaultHttpPort)) } // add predictor rule - predictorHost, err := generateIngressHost(ingressConfig, isvc, string(constants.Predictor), false, predictorName) + predictorHost, err := generateIngressHost(ingressConfig, isvc, isvcConfig, string(constants.Predictor), false, predictorName) if err != nil { return nil, fmt.Errorf("failed creating predictor ingress host: %w", err) } @@ -299,7 +305,7 @@ func (r *RawIngressReconciler) Reconcile(isvc *v1beta1.InferenceService) error { isInternal = true } if !isInternal && !r.ingressConfig.DisableIngressCreation { - ingress, err := createRawIngress(r.scheme, isvc, r.ingressConfig, r.client) + ingress, err := createRawIngress(r.scheme, isvc, r.ingressConfig, r.client, r.isvcConfig) if ingress == nil { return nil } diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/knative/ksvc_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/knative/ksvc_reconciler.go index 011145f8609..fe929e61ad1 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/knative/ksvc_reconciler.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/knative/ksvc_reconciler.go @@ -61,11 +61,12 @@ func NewKsvcReconciler(client client.Client, componentMeta metav1.ObjectMeta, componentExt *v1beta1.ComponentExtensionSpec, podSpec *corev1.PodSpec, - componentStatus v1beta1.ComponentStatusSpec) *KsvcReconciler { + componentStatus v1beta1.ComponentStatusSpec, + disallowedLabelList []string) *KsvcReconciler { return &KsvcReconciler{ client: client, scheme: scheme, - Service: createKnativeService(componentMeta, componentExt, podSpec, componentStatus), + Service: createKnativeService(componentMeta, componentExt, podSpec, componentStatus, disallowedLabelList), componentExt: componentExt, componentStatus: componentStatus, } @@ -74,7 +75,8 @@ func NewKsvcReconciler(client client.Client, func createKnativeService(componentMeta metav1.ObjectMeta, componentExtension *v1beta1.ComponentExtensionSpec, podSpec *corev1.PodSpec, - componentStatus v1beta1.ComponentStatusSpec) *knservingv1.Service { + componentStatus v1beta1.ComponentStatusSpec, + disallowedLabelList []string) *knservingv1.Service { annotations := componentMeta.GetAnnotations() if componentExtension.MinReplicas == nil { @@ -113,7 +115,11 @@ func createKnativeService(componentMeta metav1.ObjectMeta, lastRolledoutRevision := componentStatus.LatestRolledoutRevision // Log component status and canary traffic percent - log.Info("revision status:", "LatestRolledoutRevision", componentStatus.LatestRolledoutRevision, "LatestReadyRevision", componentStatus.LatestReadyRevision, "LatestCreatedRevision", componentStatus.LatestCreatedRevision, "PreviousRolledoutRevision", componentStatus.PreviousRolledoutRevision, "CanaryTrafficPercent", componentExtension.CanaryTrafficPercent) + log.Info("revision status:", "LatestRolledoutRevision", componentStatus.LatestRolledoutRevision, + "LatestReadyRevision", componentStatus.LatestReadyRevision, + "LatestCreatedRevision", componentStatus.LatestCreatedRevision, + "PreviousRolledoutRevision", componentStatus.PreviousRolledoutRevision, + "CanaryTrafficPercent", componentExtension.CanaryTrafficPercent) trafficTargets := []knservingv1.TrafficTarget{} // Split traffic when canary traffic percent is specified @@ -138,7 +144,7 @@ func createKnativeService(componentMeta metav1.ObjectMeta, trafficTargets = append(trafficTargets, canaryTarget) } } else { - // blue green rollout + // blue-green rollout latestTarget := knservingv1.TrafficTarget{ LatestRevision: proto.Bool(true), Percent: proto.Int64(100), @@ -148,8 +154,9 @@ func createKnativeService(componentMeta metav1.ObjectMeta, } trafficTargets = append(trafficTargets, latestTarget) } + labels := utils.Filter(componentMeta.Labels, func(key string) bool { - return !utils.Includes(constants.RevisionTemplateLabelDisallowedList, key) + return !utils.Includes(disallowedLabelList, key) }) service := &knservingv1.Service{ diff --git a/pkg/controller/v1beta1/inferenceservice/reconcilers/service/service_reconciler.go b/pkg/controller/v1beta1/inferenceservice/reconcilers/service/service_reconciler.go index 0d42ca4c5c2..afdd3bbf1fd 100644 --- a/pkg/controller/v1beta1/inferenceservice/reconcilers/service/service_reconciler.go +++ b/pkg/controller/v1beta1/inferenceservice/reconcilers/service/service_reconciler.go @@ -21,9 +21,11 @@ import ( "fmt" "sort" "strconv" + "strings" "github.com/kserve/kserve/pkg/apis/serving/v1beta1" "github.com/kserve/kserve/pkg/constants" + "github.com/kserve/kserve/pkg/utils" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierr "k8s.io/apimachinery/pkg/api/errors" @@ -59,6 +61,21 @@ func NewServiceReconciler(client client.Client, } } +// isGrpcPort checks if the port is a grpc port or not by port name +func isGrpcPort(port corev1.ContainerPort) bool { + if strings.Contains(port.Name, "grpc") || strings.Contains(port.Name, "h2c") { + return true + } + return false +} + +func getAppProtocol(port corev1.ContainerPort) *string { + if isGrpcPort(port) { + return utils.ToPointer("kubernetes.io/h2c") + } + return nil +} + func createService(componentMeta metav1.ObjectMeta, componentExt *v1beta1.ComponentExtensionSpec, podSpec *corev1.PodSpec, multiNodeEnabled bool, serviceConfig *v1beta1.ServiceConfig) []*corev1.Service { var svcList []*corev1.Service @@ -109,7 +126,8 @@ func createDefaultSvc(componentMeta metav1.ObjectMeta, componentExt *v1beta1.Com Type: intstr.Int, IntVal: container.Ports[0].ContainerPort, }, - Protocol: container.Ports[0].Protocol, + Protocol: container.Ports[0].Protocol, + AppProtocol: getAppProtocol(container.Ports[0]), } if len(servicePort.Name) == 0 { servicePort.Name = "http" @@ -128,7 +146,8 @@ func createDefaultSvc(componentMeta metav1.ObjectMeta, componentExt *v1beta1.Com Type: intstr.Int, IntVal: port.ContainerPort, }, - Protocol: port.Protocol, + Protocol: port.Protocol, + AppProtocol: getAppProtocol(port), } servicePorts = append(servicePorts, servicePort) } diff --git a/pkg/controller/v1beta1/inferenceservice/suite_test.go b/pkg/controller/v1beta1/inferenceservice/suite_test.go index 058ce3f7d54..a5957f4de12 100644 --- a/pkg/controller/v1beta1/inferenceservice/suite_test.go +++ b/pkg/controller/v1beta1/inferenceservice/suite_test.go @@ -36,12 +36,12 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" kfservingv1alpha1 "github.com/kserve/kserve/pkg/apis/serving/v1alpha1" "github.com/kserve/kserve/pkg/apis/serving/v1beta1" "github.com/kserve/kserve/pkg/constants" pkgtest "github.com/kserve/kserve/pkg/testing" - routev1 "github.com/openshift/api/route/v1" ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to @@ -82,7 +82,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) err = netv1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = routev1.AddToScheme(scheme.Scheme) + err = gatewayapiv1.Install(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) diff --git a/pkg/controller/v1beta1/inferenceservice/utils/utils.go b/pkg/controller/v1beta1/inferenceservice/utils/utils.go index 8cb710249de..243d50d4658 100644 --- a/pkg/controller/v1beta1/inferenceservice/utils/utils.go +++ b/pkg/controller/v1beta1/inferenceservice/utils/utils.go @@ -49,7 +49,7 @@ import ( // Constants var ( - SupportedStorageURIPrefixList = []string{"gs://", "s3://", "pvc://", "file://", "https://", "http://", "hdfs://", "webhdfs://", "oci://"} + SupportedStorageURIPrefixList = []string{"gs://", "s3://", "pvc://", "file://", "https://", "http://", "hdfs://", "webhdfs://", "oci://", "hf://"} ) const ( diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index 56e61580aba..7c0bd5e2242 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -96,6 +96,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kserve/kserve/pkg/apis/serving/v1beta1.PodSpec": schema_pkg_apis_serving_v1beta1_PodSpec(ref), "github.com/kserve/kserve/pkg/apis/serving/v1beta1.PredictorExtensionSpec": schema_pkg_apis_serving_v1beta1_PredictorExtensionSpec(ref), "github.com/kserve/kserve/pkg/apis/serving/v1beta1.PredictorSpec": schema_pkg_apis_serving_v1beta1_PredictorSpec(ref), + "github.com/kserve/kserve/pkg/apis/serving/v1beta1.ResourceConfig": schema_pkg_apis_serving_v1beta1_ResourceConfig(ref), "github.com/kserve/kserve/pkg/apis/serving/v1beta1.SKLearnSpec": schema_pkg_apis_serving_v1beta1_SKLearnSpec(ref), "github.com/kserve/kserve/pkg/apis/serving/v1beta1.SecurityConfig": schema_pkg_apis_serving_v1beta1_SecurityConfig(ref), "github.com/kserve/kserve/pkg/apis/serving/v1beta1.ServiceConfig": schema_pkg_apis_serving_v1beta1_ServiceConfig(ref), @@ -2673,7 +2674,7 @@ func schema_pkg_apis_serving_v1beta1_CustomExplainer(ref common.ReferenceCallbac }, "nodeName": { SchemaProps: spec.SchemaProps{ - Description: "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + Description: "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", Type: []string{"string"}, Format: "", }, @@ -2914,7 +2915,7 @@ func schema_pkg_apis_serving_v1beta1_CustomExplainer(ref common.ReferenceCallbac }, "os": { SchemaProps: spec.SchemaProps{ - Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", Ref: ref("k8s.io/api/core/v1.PodOS"), }, }, @@ -3157,7 +3158,7 @@ func schema_pkg_apis_serving_v1beta1_CustomPredictor(ref common.ReferenceCallbac }, "nodeName": { SchemaProps: spec.SchemaProps{ - Description: "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + Description: "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", Type: []string{"string"}, Format: "", }, @@ -3398,7 +3399,7 @@ func schema_pkg_apis_serving_v1beta1_CustomPredictor(ref common.ReferenceCallbac }, "os": { SchemaProps: spec.SchemaProps{ - Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", Ref: ref("k8s.io/api/core/v1.PodOS"), }, }, @@ -3641,7 +3642,7 @@ func schema_pkg_apis_serving_v1beta1_CustomTransformer(ref common.ReferenceCallb }, "nodeName": { SchemaProps: spec.SchemaProps{ - Description: "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + Description: "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", Type: []string{"string"}, Format: "", }, @@ -3882,7 +3883,7 @@ func schema_pkg_apis_serving_v1beta1_CustomTransformer(ref common.ReferenceCallb }, "os": { SchemaProps: spec.SchemaProps{ - Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", Ref: ref("k8s.io/api/core/v1.PodOS"), }, }, @@ -5526,12 +5527,49 @@ func schema_pkg_apis_serving_v1beta1_InferenceServicesConfig(ref common.Referenc Ref: ref("github.com/kserve/kserve/pkg/apis/serving/v1beta1.ExplainersConfig"), }, }, + "serviceAnnotationDisallowedList": { + SchemaProps: spec.SchemaProps{ + Description: "ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative revisions", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "serviceLabelDisallowedList": { + SchemaProps: spec.SchemaProps{ + Description: "ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "Resource configurations", + Default: map[string]interface{}{}, + Ref: ref("github.com/kserve/kserve/pkg/apis/serving/v1beta1.ResourceConfig"), + }, + }, }, Required: []string{"explainers"}, }, }, Dependencies: []string{ - "github.com/kserve/kserve/pkg/apis/serving/v1beta1.ExplainersConfig"}, + "github.com/kserve/kserve/pkg/apis/serving/v1beta1.ExplainersConfig", "github.com/kserve/kserve/pkg/apis/serving/v1beta1.ResourceConfig"}, } } @@ -5541,6 +5579,18 @@ func schema_pkg_apis_serving_v1beta1_IngressConfig(ref common.ReferenceCallback) SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ + "enableGatewayApi": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, + "kserveIngressGateway": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, "ingressGateway": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -5996,6 +6046,12 @@ func schema_pkg_apis_serving_v1beta1_LocalModelConfig(ref common.ReferenceCallba Format: "int64", }, }, + "disableVolumeManagement": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"enabled", "jobNamespace"}, }, @@ -8875,6 +8931,42 @@ func schema_pkg_apis_serving_v1beta1_PredictorSpec(ref common.ReferenceCallback) } } +func schema_pkg_apis_serving_v1beta1_ResourceConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "cpuLimit": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "memoryLimit": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "cpuRequest": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "memoryRequest": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_serving_v1beta1_SKLearnSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/openapi/swagger.json b/pkg/openapi/swagger.json index 428586dbed8..b9411b7b096 100644 --- a/pkg/openapi/swagger.json +++ b/pkg/openapi/swagger.json @@ -1475,7 +1475,7 @@ "x-kubernetes-patch-strategy": "merge" }, "nodeName": { - "description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + "description": "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", "type": "string" }, "nodeSelector": { @@ -1488,7 +1488,7 @@ "x-kubernetes-map-type": "atomic" }, "os": { - "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", "$ref": "#/definitions/v1.PodOS" }, "overhead": { @@ -1752,7 +1752,7 @@ "x-kubernetes-patch-strategy": "merge" }, "nodeName": { - "description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + "description": "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", "type": "string" }, "nodeSelector": { @@ -1765,7 +1765,7 @@ "x-kubernetes-map-type": "atomic" }, "os": { - "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", "$ref": "#/definitions/v1.PodOS" }, "overhead": { @@ -2029,7 +2029,7 @@ "x-kubernetes-patch-strategy": "merge" }, "nodeName": { - "description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", + "description": "NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename", "type": "string" }, "nodeSelector": { @@ -2042,7 +2042,7 @@ "x-kubernetes-map-type": "atomic" }, "os": { - "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", + "description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", "$ref": "#/definitions/v1.PodOS" }, "overhead": { @@ -3066,6 +3066,27 @@ "description": "Explainer configurations", "default": {}, "$ref": "#/definitions/v1beta1.ExplainersConfig" + }, + "resource": { + "description": "Resource configurations", + "default": {}, + "$ref": "#/definitions/v1beta1.ResourceConfig" + }, + "serviceAnnotationDisallowedList": { + "description": "ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative revisions", + "type": "array", + "items": { + "type": "string", + "default": "" + } + }, + "serviceLabelDisallowedList": { + "description": "ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions", + "type": "array", + "items": { + "type": "string", + "default": "" + } } } }, @@ -3088,6 +3109,9 @@ "domainTemplate": { "type": "string" }, + "enableGatewayApi": { + "type": "boolean" + }, "ingressClassName": { "type": "string" }, @@ -3100,6 +3124,9 @@ "knativeLocalGatewayService": { "type": "string" }, + "kserveIngressGateway": { + "type": "string" + }, "localGateway": { "type": "string" }, @@ -3305,6 +3332,9 @@ "defaultJobImage": { "type": "string" }, + "disableVolumeManagement": { + "type": "boolean" + }, "enabled": { "type": "boolean", "default": false @@ -4944,6 +4974,23 @@ } } }, + "v1beta1.ResourceConfig": { + "type": "object", + "properties": { + "cpuLimit": { + "type": "string" + }, + "cpuRequest": { + "type": "string" + }, + "memoryLimit": { + "type": "string" + }, + "memoryRequest": { + "type": "string" + } + } + }, "v1beta1.SKLearnSpec": { "description": "SKLearnSpec defines arguments for configuring SKLearn model serving.", "type": "object", diff --git a/pkg/testing/envtest_setup.go b/pkg/testing/envtest_setup.go index ea77d3af18c..47f9c1b307f 100644 --- a/pkg/testing/envtest_setup.go +++ b/pkg/testing/envtest_setup.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/manager" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) var log = logf.Log.WithName("TestingEnvSetup") @@ -54,6 +55,10 @@ func SetupEnvTest(crdDirectoryPaths []string) *envtest.Environment { if err := istioclientv1beta1.SchemeBuilder.AddToScheme(scheme.Scheme); err != nil { log.Error(err, "Failed to add istio scheme") } + + if err := gatewayapiv1.Install(scheme.Scheme); err != nil { + log.Error(err, "Failed to add gateway scheme") + } return t } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 68a9e4a3f52..2d8334b5e2a 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -310,3 +310,9 @@ func IsValidCustomGPUArray(s string) bool { return true } + +// ToPointer returns a pointer to the value passed in +func ToPointer[T any](value T) *T { + tmp := value + return &tmp +} diff --git a/python/VERSION b/python/VERSION index a803cc227fe..8185f23c2c0 100644 --- a/python/VERSION +++ b/python/VERSION @@ -1 +1 @@ -0.14.0 +0.15.0rc0 diff --git a/python/aiffairness/poetry.lock b/python/aiffairness/poetry.lock index 00622cadd15..990399ebb50 100644 --- a/python/aiffairness/poetry.lock +++ b/python/aiffairness/poetry.lock @@ -950,7 +950,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/aiffairness/pyproject.toml b/python/aiffairness/pyproject.toml index 31d38a155d5..069525e78fc 100644 --- a/python/aiffairness/pyproject.toml +++ b/python/aiffairness/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aifserver" -version = "0.14.0" +version = "0.15.0rc0" description = "'Model Server implementation for AI fairness. Not intended for use outside KServe Frameworks Images." authors = ["Andrew Butler "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/artexplainer/poetry.lock b/python/artexplainer/poetry.lock index 10536911b93..343ad2198a7 100644 --- a/python/artexplainer/poetry.lock +++ b/python/artexplainer/poetry.lock @@ -724,7 +724,7 @@ rich = "*" [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/artexplainer/pyproject.toml b/python/artexplainer/pyproject.toml index f75663e19b0..b225f762186 100644 --- a/python/artexplainer/pyproject.toml +++ b/python/artexplainer/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "artserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for AI Robustness Toolbox. Not intended for use outside KServe Frameworks Images." authors = ["Andrew Butler "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/custom_model/poetry.lock b/python/custom_model/poetry.lock index e55c18416e2..9b280c479e5 100644 --- a/python/custom_model/poetry.lock +++ b/python/custom_model/poetry.lock @@ -13,112 +13,112 @@ files = [ [[package]] name = "aiohttp" -version = "3.10.5" +version = "3.10.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5077b1a5f40ffa3ba1f40d537d3bec4383988ee51fbba6b74aa8fb1bc466599e"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d6a14a4d93b5b3c2891fca94fa9d41b2322a68194422bef0dd5ec1e57d7d298"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffbfde2443696345e23a3c597049b1dd43049bb65337837574205e7368472177"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20b3d9e416774d41813bc02fdc0663379c01817b0874b932b81c7f777f67b217"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b943011b45ee6bf74b22245c6faab736363678e910504dd7531a58c76c9015a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48bc1d924490f0d0b3658fe5c4b081a4d56ebb58af80a6729d4bd13ea569797a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e12eb3f4b1f72aaaf6acd27d045753b18101524f72ae071ae1c91c1cd44ef115"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14ebc419a568c2eff3c1ed35f634435c24ead2fe19c07426af41e7adb68713a"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72b191cdf35a518bfc7ca87d770d30941decc5aaf897ec8b484eb5cc8c7706f3"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ab2328a61fdc86424ee540d0aeb8b73bbcad7351fb7cf7a6546fc0bcffa0038"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa93063d4af05c49276cf14e419550a3f45258b6b9d1f16403e777f1addf4519"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30283f9d0ce420363c24c5c2421e71a738a2155f10adbb1a11a4d4d6d2715cfc"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e5358addc8044ee49143c546d2182c15b4ac3a60be01c3209374ace05af5733d"}, + {file = "aiohttp-3.10.11-cp310-cp310-win32.whl", hash = "sha256:e1ffa713d3ea7cdcd4aea9cddccab41edf6882fa9552940344c44e59652e1120"}, + {file = "aiohttp-3.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:778cbd01f18ff78b5dd23c77eb82987ee4ba23408cbed233009fd570dda7e674"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:80ff08556c7f59a7972b1e8919f62e9c069c33566a6d28586771711e0eea4f07"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c8f96e9ee19f04c4914e4e7a42a60861066d3e1abf05c726f38d9d0a466e695"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb8601394d537da9221947b5d6e62b064c9a43e88a1ecd7414d21a1a6fba9c24"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea224cf7bc2d8856d6971cea73b1d50c9c51d36971faf1abc169a0d5f85a382"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9503f79e12d5d80b3efd4d01312853565c05367493379df76d2674af881caa"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f449a50cc33f0384f633894d8d3cd020e3ccef81879c6e6245c3c375c448625"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82052be3e6d9e0c123499127782a01a2b224b8af8c62ab46b3f6197035ad94e9"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20063c7acf1eec550c8eb098deb5ed9e1bb0521613b03bb93644b810986027ac"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:489cced07a4c11488f47aab1f00d0c572506883f877af100a38f1fedaa884c3a"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea9b3bab329aeaa603ed3bf605f1e2a6f36496ad7e0e1aa42025f368ee2dc07b"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ca117819d8ad113413016cb29774b3f6d99ad23c220069789fc050267b786c16"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2dfb612dcbe70fb7cdcf3499e8d483079b89749c857a8f6e80263b021745c730"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9b615d3da0d60e7d53c62e22b4fd1c70f4ae5993a44687b011ea3a2e49051b8"}, + {file = "aiohttp-3.10.11-cp311-cp311-win32.whl", hash = "sha256:29103f9099b6068bbdf44d6a3d090e0a0b2be6d3c9f16a070dd9d0d910ec08f9"}, + {file = "aiohttp-3.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:236b28ceb79532da85d59aa9b9bf873b364e27a0acb2ceaba475dc61cffb6f3f"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4"}, + {file = "aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb"}, + {file = "aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:703938e22434d7d14ec22f9f310559331f455018389222eed132808cd8f44127"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bc50b63648840854e00084c2b43035a62e033cb9b06d8c22b409d56eb098413"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f0463bf8b0754bc744e1feb61590706823795041e63edf30118a6f0bf577461"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6c6dec398ac5a87cb3a407b068e1106b20ef001c344e34154616183fe684288"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcaf2d79104d53d4dcf934f7ce76d3d155302d07dae24dff6c9fffd217568067"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25fd5470922091b5a9aeeb7e75be609e16b4fba81cdeaf12981393fb240dd10e"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbde2ca67230923a42161b1f408c3992ae6e0be782dca0c44cb3206bf330dee1"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:249c8ff8d26a8b41a0f12f9df804e7c685ca35a207e2410adbd3e924217b9006"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878ca6a931ee8c486a8f7b432b65431d095c522cbeb34892bee5be97b3481d0f"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8663f7777ce775f0413324be0d96d9730959b2ca73d9b7e2c2c90539139cbdd6"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd3f10b01f0c31481fba8d302b61603a2acb37b9d30e1d14e0f5a58b7b18a31"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e8d8aad9402d3aa02fdc5ca2fe68bcb9fdfe1f77b40b10410a94c7f408b664d"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38e3c4f80196b4f6c3a85d134a534a56f52da9cb8d8e7af1b79a32eefee73a00"}, + {file = "aiohttp-3.10.11-cp313-cp313-win32.whl", hash = "sha256:fc31820cfc3b2863c6e95e14fcf815dc7afe52480b4dc03393c4873bb5599f71"}, + {file = "aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74baf1a7d948b3d640badeac333af581a367ab916b37e44cf90a0334157cdfd2"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:473aebc3b871646e1940c05268d451f2543a1d209f47035b594b9d4e91ce8339"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c2f746a6968c54ab2186574e15c3f14f3e7f67aef12b761e043b33b89c5b5f95"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d110cabad8360ffa0dec8f6ec60e43286e9d251e77db4763a87dcfe55b4adb92"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0099c7d5d7afff4202a0c670e5b723f7718810000b4abcbc96b064129e64bc7"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0316e624b754dbbf8c872b62fe6dcb395ef20c70e59890dfa0de9eafccd2849d"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5f7ab8baf13314e6b2485965cbacb94afff1e93466ac4d06a47a81c50f9cca"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c891011e76041e6508cbfc469dd1a8ea09bc24e87e4c204e05f150c4c455a5fa"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9208299251370ee815473270c52cd3f7069ee9ed348d941d574d1457d2c73e8b"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:459f0f32c8356e8125f45eeff0ecf2b1cb6db1551304972702f34cd9e6c44658"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:14cdc8c1810bbd4b4b9f142eeee23cda528ae4e57ea0923551a9af4820980e39"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:971aa438a29701d4b34e4943e91b5e984c3ae6ccbf80dd9efaffb01bd0b243a9"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9a309c5de392dfe0f32ee57fa43ed8fc6ddf9985425e84bd51ed66bb16bce3a7"}, + {file = "aiohttp-3.10.11-cp38-cp38-win32.whl", hash = "sha256:9ec1628180241d906a0840b38f162a3215114b14541f1a8711c368a8739a9be4"}, + {file = "aiohttp-3.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:9c6e0ffd52c929f985c7258f83185d17c76d4275ad22e90aa29f38e211aacbec"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc493a2e5d8dc79b2df5bec9558425bcd39aff59fc949810cbd0832e294b106"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3e70f24e7d0405be2348da9d5a7836936bf3a9b4fd210f8c37e8d48bc32eca6"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968b8fb2a5eee2770eda9c7b5581587ef9b96fbdf8dcabc6b446d35ccc69df01"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deef4362af9493d1382ef86732ee2e4cbc0d7c005947bd54ad1a9a16dd59298e"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:686b03196976e327412a1b094f4120778c7c4b9cff9bce8d2fdfeca386b89829"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bf6d027d9d1d34e1c2e1645f18a6498c98d634f8e373395221121f1c258ace8"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:099fd126bf960f96d34a760e747a629c27fb3634da5d05c7ef4d35ef4ea519fc"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73c4d3dae0b4644bc21e3de546530531d6cdc88659cdeb6579cd627d3c206aa"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c5580f3c51eea91559db3facd45d72e7ec970b04528b4709b1f9c2555bd6d0b"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf6429f0caabfd8a30c4e2eaecb547b3c340e4730ebfe25139779b9815ba138"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d97187de3c276263db3564bb9d9fad9e15b51ea10a371ffa5947a5ba93ad6777"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0acafb350cfb2eba70eb5d271f55e08bd4502ec35e964e18ad3e7d34d71f7261"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c13ed0c779911c7998a58e7848954bd4d63df3e3575f591e321b19a2aec8df9f"}, + {file = "aiohttp-3.10.11-cp39-cp39-win32.whl", hash = "sha256:22b7c540c55909140f63ab4f54ec2c20d2635c0289cdd8006da46f3327f971b9"}, + {file = "aiohttp-3.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:7b26b1551e481012575dab8e3727b16fe7dd27eb2711d2e63ced7368756268fb"}, + {file = "aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7"}, ] [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -960,7 +960,7 @@ referencing = ">=0.31.0" [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" @@ -1835,6 +1835,97 @@ files = [ [package.extras] twisted = ["twisted"] +[[package]] +name = "propcache" +version = "0.2.1" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +files = [ + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, +] + [[package]] name = "proto-plus" version = "1.24.0" @@ -3102,106 +3193,99 @@ files = [ [[package]] name = "yarl" -version = "1.9.4" +version = "1.18.3" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [metadata] lock-version = "2.0" diff --git a/python/custom_model/pyproject.toml b/python/custom_model/pyproject.toml index 35e90691887..9520efc375a 100644 --- a/python/custom_model/pyproject.toml +++ b/python/custom_model/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "custom-model" -version = "0.14.0" +version = "0.15.0rc0" description = "Custom model implementation. Not intended for use outside KServe Frameworks Images." authors = ["The KServe Authors"] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/custom_tokenizer/poetry.lock b/python/custom_tokenizer/poetry.lock index 4615f442a9f..a40b4f3230b 100644 --- a/python/custom_tokenizer/poetry.lock +++ b/python/custom_tokenizer/poetry.lock @@ -518,7 +518,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/custom_tokenizer/pyproject.toml b/python/custom_tokenizer/pyproject.toml index b3be1ae1d77..0bb079965cd 100644 --- a/python/custom_tokenizer/pyproject.toml +++ b/python/custom_tokenizer/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "custom_tokenizer" -version = "0.14.0" +version = "0.15.0rc0" description = "Custom Tokenizer Examples. Not intended for use outside KServe Frameworks Images." authors = ["Dan Sun "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/custom_transformer/poetry.lock b/python/custom_transformer/poetry.lock index 65dad043721..5596e1eb67b 100644 --- a/python/custom_transformer/poetry.lock +++ b/python/custom_transformer/poetry.lock @@ -604,7 +604,7 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/custom_transformer/pyproject.toml b/python/custom_transformer/pyproject.toml index da602893d36..fbfd38dac9c 100644 --- a/python/custom_transformer/pyproject.toml +++ b/python/custom_transformer/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "custom_transformer" -version = "0.14.0" +version = "0.15.0rc0" description = "Custom Transformer Examples. Not intended for use outside KServe Frameworks Images." authors = ["Dan Sun "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/huggingface_server.Dockerfile b/python/huggingface_server.Dockerfile index 898dbd573f8..3e0c77a1dde 100644 --- a/python/huggingface_server.Dockerfile +++ b/python/huggingface_server.Dockerfile @@ -9,7 +9,7 @@ ARG POETRY_HOME=/opt/poetry ARG POETRY_VERSION=1.8.3 # Install vllm -ARG VLLM_VERSION=0.6.3.post1 +ARG VLLM_VERSION=0.6.6.post1 RUN apt-get update && apt-get upgrade -y && apt-get install gcc python3.10-venv python3-dev -y && apt-get clean && \ rm -rf /var/lib/apt/lists/* @@ -32,7 +32,7 @@ RUN cd huggingfaceserver && poetry install --no-root --no-interaction --no-cache COPY huggingfaceserver huggingfaceserver RUN cd huggingfaceserver && poetry install --no-interaction --no-cache -RUN pip3 install vllm==${VLLM_VERSION} +RUN pip install --upgrade pip && pip install vllm==${VLLM_VERSION} FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 AS prod diff --git a/python/huggingface_server_cpu_openvino.Dockerfile b/python/huggingface_server_cpu_openvino.Dockerfile index 4230ad9e4aa..63cce928437 100644 --- a/python/huggingface_server_cpu_openvino.Dockerfile +++ b/python/huggingface_server_cpu_openvino.Dockerfile @@ -9,7 +9,7 @@ ARG POETRY_HOME=/opt/poetry ARG POETRY_VERSION=1.8.3 # Install vllm -ARG VLLM_VERSION=v0.6.3.post1 +ARG VLLM_VERSION=v0.6.4.post1 RUN apt-get update -y && apt-get install -y \ gcc python3.10-venv python3-dev python3-pip \ diff --git a/python/huggingfaceserver/health_check.py b/python/huggingfaceserver/health_check.py index 9c95c6c2e4e..27448dbad23 100644 --- a/python/huggingfaceserver/health_check.py +++ b/python/huggingfaceserver/health_check.py @@ -13,41 +13,88 @@ # limitations under the License. import argparse +import sys +import time +import os + import ray import requests -import sys from kserve.logging import logger -def initialize_ray_cluster(): - if not ray.is_initialized(): # Check if Ray is already initialized - ray.init(address="auto") - return "Ray initialized" - else: - return "Ray already initialized" +def initialize_ray_cluster(ray_address="auto"): + try: + if ray.is_initialized(): # Check if Ray is already initialized + return + else: + ray.init(address=ray_address) + return + except Exception as e: + logger.error(f"Failed to initialize Ray: {e}") + sys.exit(1) + + +def show_ray_cluster_status(ray_address="auto"): + initialize_ray_cluster(ray_address) + try: + resources = ray.cluster_resources() + logger.info("Cluster resources:", resources) + except Exception as e: + logger.error(f"Error getting Ray nodes status: {e}") -def verify_status(result): - if result == "Healthy": +def verify_status(result, probe_type): + if result in ("Healthy", True): + logger.info(f"{probe_type} Probe: Healthy") sys.exit(0) else: + logger.error(f"{probe_type} Probe: Unhealthy") sys.exit(1) # Function for startup check using Ray API -def check_startup(): - try: - initialize_ray_cluster() - logger.info("Ray is accessible") +def check_registered_node_and_runtime_health( + pipeline_parallel_size, health_check_url, ray_address="auto" +): + initialize_ray_cluster(ray_address) + # Check if the registered nodes count matches PIPELINE_PARALLEL_SIZE + check_registered_nodes_status = check_registered_nodes( + pipeline_parallel_size, ray_address + ) + + # Check if server health return 200 + check_runtime_health_status = check_runtime_health(health_check_url) + logger.debug( + f"check_registered_nodes_status: {check_registered_nodes_status},check_runtime_health_status: {check_runtime_health_status}" + ) + + if ( + check_registered_nodes_status == "Healthy" + and check_runtime_health_status == "Healthy" + ): return "Healthy" - except Exception as e: - logger.error(f"Ray is NOT accessible: {e}") + else: + return "Unhealthy" + + +def check_registered_node_and_runtime_models( + pipeline_parallel_size, runtime_url, ray_address, isvc_name +): + result1 = check_registered_nodes(pipeline_parallel_size, ray_address) + result2 = check_runtime_models(runtime_url, isvc_name) + logger.debug(f"check_registered_nodes: {result1}, check_runtime_models: {result2}") + # Check both results + if (result1 == "Healthy" or result1 is True) and ( + result2 == "Healthy" or result2 is True + ): + return "Healthy" + else: return "Unhealthy" -def check_gpu_usage(probe_type): +def check_gpu_usage(ray_address="auto"): try: - initialize_ray_cluster() + initialize_ray_cluster(ray_address) nodes = ray.nodes() total_gpus = 0 used_gpus = 0 @@ -58,130 +105,200 @@ def check_gpu_usage(probe_type): # Determine health status based on GPU usage if total_gpus == 0 or total_gpus != used_gpus: logger.error( - f"{probe_type}: Unhealthy - Used: {used_gpus}, Total: {total_gpus}" + f"GPU Usage: Unhealthy - Used: {used_gpus}, Total: {total_gpus}" ) return "Unhealthy" else: - logger.info( - f"{probe_type}: Healthy - Used: {used_gpus}, Total: {total_gpus}" - ) + logger.info(f"GPU Usage: Healthy - Used: {used_gpus}, Total: {total_gpus}") return "Healthy" except Exception as e: - logger.error(f"{probe_type}: Error - Failed to get GPU status: {str(e)}") + logger.error(f"GPU Usage: Error - Failed to get GPU status: {str(e)}") return "Unhealthy" -def check_registered_nodes(pipeline_parallel_size): +def check_registered_nodes( + pipeline_parallel_size, ray_address="auto", retries=0, interval=2 +): try: - initialize_ray_cluster() - # Get list of alive nodes - nodes = ray.nodes() - registered_node_count = len([node for node in nodes if node["Alive"]]) + pipeline_parallel_size = int(pipeline_parallel_size) # Ensure it's an integer + except ValueError: + logger.error(f"Invalid pipeline_parallel_size: {pipeline_parallel_size}") + return "Unhealthy" - # Check if the registered nodes count matches PIPELINE_PARALLEL_SIZE - if registered_node_count != int(pipeline_parallel_size): - logger.error( - f"Unhealthy - Registered nodes count ({registered_node_count}) does not match PIPELINE_PARALLEL_SIZE ({pipeline_parallel_size})." + for attempt in range(1, retries + 2): + try: + initialize_ray_cluster(ray_address) + # Get list of alive nodes + nodes = ray.nodes() + registered_node_count = len([node for node in nodes if node["Alive"]]) + logger.debug( + f"registered_node_count: {registered_node_count}, pipeline_parallel_size: {pipeline_parallel_size}" ) - return "Unhealthy" - else: - logger.info( - f"Healthy - Registered nodes count ({registered_node_count}) match PIPELINE_PARALLEL_SIZE ({pipeline_parallel_size})." - ) - return "Healthy" - except Exception as e: - logger.error(f"Error checking registered nodes: {str(e)}") - return "Unhealthy" + # Check if the registered nodes count matches PIPELINE_PARALLEL_SIZE + if not registered_node_count >= pipeline_parallel_size: + logger.error( + f"Waiting - Registered nodes count ({registered_node_count}) does not match PIPELINE_PARALLEL_SIZE ({pipeline_parallel_size})." + ) + else: + logger.info( + f"Success - Registered nodes count ({registered_node_count}) matches PIPELINE_PARALLEL_SIZE ({pipeline_parallel_size})." + ) + return "Healthy" + except Exception as e: + logger.error(f"Error checking registered nodes: {str(e)}") -def check_runtime_health(health_check_url): - # Check if Huggingface server health - try: - response = requests.get(health_check_url, timeout=5) - if response.status_code != 200: - logger.error(f"Hugging Face server({health_check_url}) is not reachable.") - return "Unhealthy" - else: - logger.info(f"Hugging Face server({health_check_url}) is reachable.") - return "Healthy" - except requests.RequestException: - logger.error(f"Hugging Face server({health_check_url}) is not reachable.") - return "Unhealthy" + if attempt < retries: + time.sleep(interval) + logger.error( + "Max retries reached. Node count did not match the expected pipeline parallel size." + ) + return "Unhealthy" -def check_readiness(pipeline_parallel_size, health_check_url): - # Check if the registered nodes count matches PIPELINE_PARALLEL_SIZE - check_registered_nodes_status = check_registered_nodes(pipeline_parallel_size) +def check_runtime_health(health_check_url, retries=1, interval=1): + # Check if runtime server health + for attempt in range(1, retries + 2): + try: + response = requests.get(health_check_url, timeout=5) + if response.status_code != 200: + logger.error(f"Server({health_check_url}) did not return 200 code.") + else: + logger.info(f"Server({health_check_url}) is reachable.") + return "Healthy" + except requests.RequestException: + logger.error(f"Server({health_check_url}) is not reachable.") - # Check GPU usage - check_gpu_usage_status = check_gpu_usage("Readiness Probe") + if attempt < retries: + time.sleep(interval) - # Check if Huggingface server health - check_runtime_health_status = check_runtime_health(health_check_url) + return "Unhealthy" - if ( - check_registered_nodes_status == "Healthy" - and check_gpu_usage_status == "Healthy" - and check_runtime_health_status == "Healthy" - ): - logger.info("Readiness Probe: Healthy") - return "Healthy" - else: - logger.error("Readiness Probe: Unhealthy") - return "Unhealthy" + +def check_runtime_models(health_check_url, isvc_name, retries=1, interval=1): + # Check if runtime server health + for attempt in range(1, retries + 2): + try: + response = requests.get(health_check_url, timeout=5) + if isvc_name in response.text: + logger.info(f"Model({isvc_name}) is Ready to serve") + return True + else: + logger.error(f"Model({isvc_name}) is Not ready to serve") + except requests.RequestException: + logger.error(f"Server({health_check_url}) is not reachable.") + + if attempt < retries: + time.sleep(interval) + + return False # Main logic to handle CLI commands using argparse def main(): + # Get default values from environment variables if available + default_ray_address = os.getenv("RAY_ADDRESS", "auto") + default_isvc_name = os.getenv("ISVC_NAME", "") + default_pipeline_parallel_size = int( + os.getenv("PIPELINE_PARALLEL_SIZE", 2) + ) # Default to 2 if not set + # Create the top-level parser - parser = argparse.ArgumentParser(description="Perform multinode health checks.") + parser = argparse.ArgumentParser(description="Perform multinode operations") + parser.add_argument( + "--ray_address", default=default_ray_address, help="Ray head address" + ) + parser.add_argument( + "--isvc_name", default=default_isvc_name, help="InferenceService name" + ) - # Define subcommands (readiness, startup, gpu_usage, registered_nodes) + # Define subcommands (readiness,,liveness, startup, gpu_usage, registered_nodes) subparsers = parser.add_subparsers(dest="command", help="Sub-command to run") - # Readiness subcommand - readiness_parser = subparsers.add_parser( - "readiness", help="Perform readiness check" + # Check runtime health subcommand + runtime_health_parser = subparsers.add_parser( + "runtime_health", help="Check runtime health" ) - readiness_parser.add_argument( - "pipeline_parallel_size", type=int, help="Pipeline parallel size" + runtime_health_parser.add_argument("--health_check_url", help="Health check URL") + runtime_health_parser.add_argument("--probe_name", help="Probe name") + + # Check if registered node is the same as pipelineParalleSize + reigstered_node_parser = subparsers.add_parser( + "registered_nodes", + help="Check if registered nodes are the same as pipeline parallel size", ) - readiness_parser.add_argument("health_check_url", help="Health check URL") + reigstered_node_parser.add_argument( + "--pipeline_parallel_size", + type=int, + default=default_pipeline_parallel_size, + help="Pipeline parallel size", + ) + reigstered_node_parser.add_argument( + "--retries", type=int, default=0, help="Pipeline parallel size" + ) + reigstered_node_parser.add_argument("--probe_name", help="Probe name") - # Liveness subcommand - subparsers.add_parser("liveness", help="Perform liveness check") - # Startup subcommand - subparsers.add_parser("startup", help="Perform startup check") - # GPU Usage subcommand - subparsers.add_parser("gpu_usage", help="Check GPU usage") + # Check if registered node is the same as pipelineParalleSize/ runtime health subcommand + registered_node_and_runtime_health_parser = subparsers.add_parser( + "registered_node_and_runtime_health", + help="Check node counts and runtime health", + ) + registered_node_and_runtime_health_parser.add_argument( + "--pipeline_parallel_size", + type=int, + default=default_pipeline_parallel_size, + help="Pipeline parallel size", + ) + registered_node_and_runtime_health_parser.add_argument( + "--health_check_url", help="Health check URL" + ) + registered_node_and_runtime_health_parser.add_argument( + "--probe_name", help="Probe name" + ) - # Registered Nodes subcommand - registered_nodes_parser = subparsers.add_parser( - "registered_nodes", help="Check registered nodes" + # Check if registered node is the same as pipelineParalleSize/ model loaded on runtime subcommand + registered_node_and_runtime_models_parser = subparsers.add_parser( + "registered_node_and_runtime_models", + help="Check node counts and loaded model on runtime", + ) + registered_node_and_runtime_models_parser.add_argument( + "--pipeline_parallel_size", + type=int, + default=default_pipeline_parallel_size, + help="Pipeline parallel size", + ) + registered_node_and_runtime_models_parser.add_argument( + "--runtime_url", help="Health check URL" ) - registered_nodes_parser.add_argument( - "pipeline_parallel_size", type=int, help="Pipeline parallel size" + registered_node_and_runtime_models_parser.add_argument( + "--probe_name", help="Probe name" ) # Parse the arguments args = parser.parse_args() # Route to appropriate function based on command using if-elif-else - if args.command == "readiness": - result = check_readiness(args.pipeline_parallel_size, args.health_check_url) - verify_status(result) - elif args.command == "startup": - result = check_startup() - verify_status(result) - elif args.command == "liveness": - result = check_gpu_usage("Liveness Probe") - verify_status(result) - elif args.command == "gpu_usage": - result = check_gpu_usage("GPU Usage") - verify_status(result) + if args.command == "runtime_health": + result = check_runtime_health(args.health_check_url) + verify_status(result, args.probe_name) + elif args.command == "registered_node_and_runtime_health": + result = check_registered_node_and_runtime_health( + args.pipeline_parallel_size, args.health_check_url, args.ray_address + ) + verify_status(result, args.probe_name) + elif args.command == "registered_node_and_runtime_models": + result = check_registered_node_and_runtime_models( + args.pipeline_parallel_size, + args.runtime_url, + args.ray_address, + args.isvc_name, + ) + verify_status(result, args.probe_name) elif args.command == "registered_nodes": - result = check_registered_nodes(args.pipeline_parallel_size) - verify_status(result) + result = check_registered_nodes( + args.pipeline_parallel_size, args.ray_address, args.retries + ) + verify_status(result, args.probe_name) else: parser.print_help() diff --git a/python/huggingfaceserver/huggingfaceserver/__main__.py b/python/huggingfaceserver/huggingfaceserver/__main__.py index 1e334187286..864832192c1 100644 --- a/python/huggingfaceserver/huggingfaceserver/__main__.py +++ b/python/huggingfaceserver/huggingfaceserver/__main__.py @@ -14,7 +14,7 @@ import argparse from pathlib import Path -from typing import cast +from typing import cast, Union import torch import kserve @@ -50,6 +50,26 @@ def list_of_strings(arg): return arg.split(",") +def get_model_id_or_path(args: argparse.Namespace) -> Union[str, Path]: + # If --model_id is specified then pass model_id to HF API, otherwise load the model from /mnt/models + if args.model_id: + return cast(str, args.model_id) + return Path(Storage.download(args.model_dir)) + + +def is_vllm_backend_enabled( + args: argparse.Namespace, model_id_or_path: Union[str, Path] +) -> bool: + return ( + (args.backend == Backend.vllm or args.backend == Backend.auto) + and vllm_available() + and infer_vllm_supported_from_model_architecture( + model_id_or_path, + trust_remote_code=args.trust_remote_code, + ) + ) + + try: from vllm.utils import FlexibleArgumentParser @@ -110,7 +130,6 @@ def list_of_strings(arg): default=None, help="the tensor input names passed to the model", ) -parser.add_argument("--task", required=False, help="The ML task name") available_backends = ", ".join(f"'{b.name}'" for b in Backend) parser.add_argument( "--backend", @@ -138,7 +157,6 @@ def list_of_strings(arg): "ID numbers being printed in log." "\n\nDefault: Unlimited", ) -parser = maybe_add_vllm_cli_parser(parser) default_dtype = "float16" if torch.cuda.is_available() else "float32" if not vllm_available(): @@ -152,6 +170,17 @@ def list_of_strings(arg): f"Defaults to float16 for GPU and float32 for CPU systems", ) +# The initial_args are required to determine whether the vLLM backend is enabled. +initial_args, _ = parser.parse_known_args() +model_id_or_path = get_model_id_or_path(initial_args) +if is_vllm_backend_enabled(initial_args, model_id_or_path): + # If vLLM backend is enabled, add the vLLM specific CLI arguments to the parser + parser = maybe_add_vllm_cli_parser(parser) +else: + # If vLLM backend is not enabled, add the task argument for Huggingface backend + parser.add_argument( + "--task", required=False, help="The ML task name for huggingface backend" + ) args, _ = parser.parse_known_args() @@ -165,11 +194,7 @@ def list_of_strings(arg): def load_model(): engine_args = None - # If --model_id is specified then pass model_id to HF API, otherwise load the model from /mnt/models - if args.model_id: - model_id_or_path = cast(str, args.model_id) - else: - model_id_or_path = Path(Storage.download(args.model_dir)) + model_id_or_path = get_model_id_or_path(args) if args.disable_log_requests: request_logger = None @@ -182,14 +207,7 @@ def load_model(): if args.backend == Backend.vllm and not vllm_available(): raise RuntimeError("Backend is set to 'vllm' but vLLM is not available") - if ( - (args.backend == Backend.vllm or args.backend == Backend.auto) - and vllm_available() - and infer_vllm_supported_from_model_architecture( - model_id_or_path, - trust_remote_code=args.trust_remote_code, - ) - ): + if is_vllm_backend_enabled(args, model_id_or_path): from .vllm.vllm_model import VLLMModel args.model = args.model_id or args.model_dir diff --git a/python/huggingfaceserver/huggingfaceserver/encoder_model.py b/python/huggingfaceserver/huggingfaceserver/encoder_model.py index 9c57f087167..3fe6368486a 100644 --- a/python/huggingfaceserver/huggingfaceserver/encoder_model.py +++ b/python/huggingfaceserver/huggingfaceserver/encoder_model.py @@ -11,10 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import base64 import pathlib -from typing import Any, Dict, Optional, Union +import struct +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, List +import pydantic import torch import torch.nn.functional as F from accelerate import init_empty_weights @@ -23,6 +26,13 @@ from kserve.logging import logger from kserve.model import PredictorConfig from kserve.protocol.infer_type import InferInput, InferRequest, InferResponse +from kserve.protocol.rest.openai import ( + EmbeddingRequest, + OpenAIEmbeddingModel, +) +from kserve.protocol.rest.openai.errors import OpenAIError, create_error_response +from kserve.protocol.rest.openai.types import Embedding, EmbeddingObject +from kserve.protocol.rest.openai.types.openapi import Usage from kserve.utils.utils import ( from_np_dtype, get_predict_input, @@ -49,7 +59,9 @@ from .utils import _get_and_verify_max_len, _mean_pooling -class HuggingfaceEncoderModel(Model): # pylint:disable=c-extension-no-member +class HuggingfaceEncoderModel( + Model, OpenAIEmbeddingModel +): # pylint:disable=c-extension-no-member task: MLTask model_config: PretrainedConfig model_id_or_path: Union[pathlib.Path, str] @@ -340,3 +352,68 @@ def _log_request(self, request_id: str, prompt: list[str]) -> None: request_id, prompt=prompt, ) + + async def create_embedding(self, request: EmbeddingRequest) -> Embedding: + params = request.params + + try: + pydantic.TypeAdapter( + Union[str, List[str], List[int], List[List[int]]] + ).validate_python(params.input) + except pydantic.ValidationError as e: + raise OpenAIError( + response=create_error_response( + "'$.input' is invalid. Please check the API reference: https://platform.openai.com/docs/api-reference.", + status_code=HTTPStatus.BAD_REQUEST, + err_type="invalid_request_error", + ) + ) from e + + # The OpenAI documentation allows the input of token lists instead of strings. As the tokenization is specific + # to the model, it is most likely different from the ones used by OpenAI (e.g., tiktoken). Libraries like + # LangChain attempt to determine the proper tokenization based on the model name and will fall back to the + # default "cl100k_base" tokenization, which will certainly not match the deployed model. Instead of silently + # accepting the mismatch, we rather raise an exception. + try: + pydantic.TypeAdapter(Union[str, List[str]]).validate_python(params.input) + except pydantic.ValidationError as e: + raise OpenAIError( + response=create_error_response( + "'input' as token lists is not supported", + status_code=HTTPStatus.NOT_IMPLEMENTED, + err_type="invalid_request_error", + ) + ) from e + + # Call the inference to determine the embedding values + context = {} + instances = params.input if isinstance(params.input, list) else [params.input] + inference_out, _ = await self({"instances": instances}, context) + embedding_out = inference_out["predictions"] + + # Calculate the input token count. Attention mask is "1" for each input token. + num_input_tokens = int(context["attention_mask"].sum()) + + # Optionally encode result to base64 + if params.encoding_format == "base64": + for i, o in enumerate(embedding_out): + embedding_bytes = [struct.pack("=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.12.0,<2.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] +[[package]] +name = "aiohttp-cors" +version = "0.7.0" +description = "CORS support for aiohttp" +optional = true +python-versions = "*" +files = [ + {file = "aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"}, + {file = "aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e"}, +] + +[package.dependencies] +aiohttp = ">=1.1" + [[package]] name = "aiosignal" -version = "1.3.1" +version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, + {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, + {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, ] [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "airportsdata" +version = "20241001" +description = "Extensive database of location and timezone data for nearly every airport and landing strip in the world." +optional = true +python-versions = ">=3.9" +files = [ + {file = "airportsdata-20241001-py3-none-any.whl", hash = "sha256:67d71cf2c5378cc17ff66b62b1e11aa2444043949c894543ac8fd8dafce192fd"}, + {file = "airportsdata-20241001.tar.gz", hash = "sha256:fa0bd143b4f4be3557cb892fa0612ef210fd91a92bd720b4d8221de576a4fa00"}, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -181,65 +192,76 @@ files = [ [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "astor" +version = "0.8.1" +description = "Read/rewrite/write Python ASTs" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, + {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, +] + [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] name = "attrs" -version = "24.2.0" +version = "24.3.0" description = "Classes Without Boilerplate" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, + {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "azure-core" -version = "1.31.0" +version = "1.32.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd"}, - {file = "azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b"}, + {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, + {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, ] [package.dependencies] @@ -270,13 +292,13 @@ typing-extensions = ">=4.0.0" [[package]] name = "azure-storage-blob" -version = "12.23.1" +version = "12.24.0" description = "Microsoft Azure Blob Storage Client Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure_storage_blob-12.23.1-py3-none-any.whl", hash = "sha256:1c2238aa841d1545f42714a5017c010366137a44a0605da2d45f770174bfc6b4"}, - {file = "azure_storage_blob-12.23.1.tar.gz", hash = "sha256:a587e54d4e39d2a27bd75109db164ffa2058fe194061e5446c5a89bca918272f"}, + {file = "azure_storage_blob-12.24.0-py3-none-any.whl", hash = "sha256:4f0bb4592ea79a2d986063696514c781c9e62be240f09f6397986e01755bc071"}, + {file = "azure_storage_blob-12.24.0.tar.gz", hash = "sha256:eaaaa1507c8c363d6e1d1342bd549938fdf1adec9b1ada8658c8f5bf3aea844e"}, ] [package.dependencies] @@ -290,13 +312,13 @@ aio = ["azure-core[aio] (>=1.30.0)"] [[package]] name = "azure-storage-file-share" -version = "12.19.0" +version = "12.20.0" description = "Microsoft Azure Azure File Share Storage Client Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure_storage_file_share-12.19.0-py3-none-any.whl", hash = "sha256:eac6cf1a454aba58af4e6ba450b36d16aa1d0c49679fb64ea8756bb896698c5b"}, - {file = "azure_storage_file_share-12.19.0.tar.gz", hash = "sha256:ea7a4174dc6c52f50ac8c30f228159fcc3675d1f8ba771b8d0efcbc310740278"}, + {file = "azure_storage_file_share-12.20.0-py3-none-any.whl", hash = "sha256:fd5c4f09d7784d68b8ed3de473b7525904f1c4b115f9cd200c838b0ee720cb5f"}, + {file = "azure_storage_file_share-12.20.0.tar.gz", hash = "sha256:f120fc67bae0a84c1b54d06faa70df351be14d1395b9a085350e833f7d347a65"}, ] [package.dependencies] @@ -355,19 +377,111 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "blake3" +version = "1.0.1" +description = "Python bindings for the Rust blake3 crate" +optional = true +python-versions = "*" +files = [ + {file = "blake3-1.0.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4b24dc5bfaaeda911e5b7dbc99f47c9c5fc84d8841656bcb043ce5c402db3088"}, + {file = "blake3-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41018d98e062931a19dc3bfa77a0f34d5dfa756d5859f4cfe678ccbe24815b36"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6727d1ea501b6ef9f159a17039df449997ce95ee79c1a2be7898b54fd09659db"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b95a859c249b32191732c7fb55d006497c0d7bcb6211ce8e187b4e7cc64d7f1e"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3e99ffccb733468cd6a68da3b148a010721eeb6517d2892c2fad01ac088d8c4"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49033a5184cfe34fbed453f85de03564dfd6ae3271e2e33de56a11d2b453c163"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:251bf7693b434d067632d0dce41466774531f369d8aadc83c23d702bcf70fb29"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8abd05d45b68bedb7341fdaaaf564c105b868cb4b89d7b29e74feb388430169e"}, + {file = "blake3-1.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7d61b5d4d7adacf9d6d22422d8bc0cee23264f8f886b39d634a522ed82c71a5"}, + {file = "blake3-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcc46d88e820ab8ac200cb0547e287458c845fd412369fd8dc89a6ed466019d6"}, + {file = "blake3-1.0.1-cp310-cp310-win32.whl", hash = "sha256:bf3ae73c25e7dbaae099ce8511b525e50d981d437dd50f7a46a98a5ae417302a"}, + {file = "blake3-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1f887aca4798ae7f1899fa3ef8c399ba889c33aa9e7ebf067e7f1ade09144481"}, + {file = "blake3-1.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f9ec05d9bd156e759fe9989c0d6e75b36410850a99296aa03eef7cd1198ca5e"}, + {file = "blake3-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46515c0b1dba02d48184417b8bae611d5c12b114f9a8b103746fb8d07b981042"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfbe2d39ef8a88a4e1937773d38f8a9b05f6328716e760342b3af0a7f3467869"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:855d9dc151017b8295fe10628b6bd8c1d10fc96f5c561fb4281faf70492a2104"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96fc1cbebc964678674c2bd27650e417a37a242ba73337ae2ef7f323e8b41b21"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a27cb7af5e337d08a5d1c3c440384911b65812509b30408c6212df9c13e3bb4"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9eee484df045753178eab4ede2c7570306ffdbf874cc5740ad08e549bd73714"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ffda996220524e1e21d1d3a13a3638d49d67c1178d3313b03ecc03c49f8432f"}, + {file = "blake3-1.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f492c253bd6f8f0ffed0d185bbbfc4ccfcaff35e6846665e40154ac949a079bb"}, + {file = "blake3-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d38b6b9ef126e25ffecb7a64307df718f6831630c95d54301932660bb39af35a"}, + {file = "blake3-1.0.1-cp311-cp311-win32.whl", hash = "sha256:a9702eed8480c30f9da660ac7ecfc43f8ab2e9f0e1f3a4097ac4045628208696"}, + {file = "blake3-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:c1adb415561df49ffc19ebd4ab36025b3c263f4813ccdbddc467e9a4ac50d307"}, + {file = "blake3-1.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0b8781fd128e8a6448beb1ecc5863617f167af3f911a8013afc0f54319a5542b"}, + {file = "blake3-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5970ec6191e4b20ff5f4e3dce9fd368599677ade0765f1b6d5fc5df859ec18e3"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9405186a6fd2d6c9d87bcf6ebc30836f56e3a37e32697e0457d7f7c6b954e166"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55917351d9b2f404ec1216be8394ec85db030294a8b0953c45c21c7b69ff10d8"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d174c9b21be3463a8aa9cc05d796cd70da7ec03c1e01d2aaa860e03e0eb3156"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8cae27f0df12b0d4387af16a9cbe1bb7d95c66d21c863706af94b05cefd0360"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef8ec9fa6d4d3446746621245090b4328dfff18f3a93c89a5ccf82a99b50accb"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99a258e5fbaf85e96bf40a7463df5acef626d69a4e79c599366cde33ea56ea6e"}, + {file = "blake3-1.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b63a8e8579ba3a5513937a114bcc2acc07a746a6b903a46070bc5d3f7d32667d"}, + {file = "blake3-1.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a49580f0ee717b55843f15c9a1ffc5f946a9cb3d15bdda4024361fdfab6ef1e6"}, + {file = "blake3-1.0.1-cp312-cp312-win32.whl", hash = "sha256:ac6f55570db7da41b29de7af120a9edfa27c2e4724e7e4ebb0aa4b41414c9e41"}, + {file = "blake3-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddcc95cd5a4db73bd97a4d21eacfc793c057baae7d5b962f182467f861d2b4a6"}, + {file = "blake3-1.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8c800eff0f5dbb13062cbe0970e3b922de473f10bd9729e166d58618b79082ad"}, + {file = "blake3-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:026b0e9c643fdc9f2fab8435b582fe59b705acdf2560197dd68c75f24c5db3a5"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d871674e43fe9cfb2a0e17267d988572f681b471c5bc7f262e35d6a56517380c"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:598905ac64221ea8823466e5fced2923eea8d6f508d61b177d3d3b00a65fdbed"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:756b4dcf4be33f1a8a518bc09b939eb7052ff00c2c118a66300ac7ae49898361"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:58e3736578577da9f0297482387f7babf5d08ab68d935d71345ad3740a219c11"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0a20efd5efd46074a7c073768e958c451985cba1c296eb79f6dd19c9d7d2173"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:795bca3208fa11d2eeb26c2cb38e9a94f06cbec9f97fe6752b82b12645e5ff22"}, + {file = "blake3-1.0.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:46486763ffe98f0296055f5e6a413bbd5822fd298c461127b28f5b87bb3cdfa5"}, + {file = "blake3-1.0.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:06ef09f7a9e3b2971e123a0bb408edaaf4c33ae5917f0c11fe05520b5d85f847"}, + {file = "blake3-1.0.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a13bb0ec647f280491d6ad9b105e5f529166d600a3f71f09412171870844792d"}, + {file = "blake3-1.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6c981943bdc8bf5eff1833fbaeafb4360b889af31deccf8f52813608d98fff78"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e7656948aba53b0e68380dc3cca6b2f93965973469ef99077f5855a0e62b9dc"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:795fe3c98ab81691c560faeac1181066931d7c14dbb8bf37bfbf4b46b9eb4e16"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f04db159714e651c7e75e457b502bb121b343b756dd251608c859963a03a22"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74789ce1273c9d80929d33474dbcc8d2f06dd2a43e98cf47b8282cdfb2567367"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352086155099ea7175b71e8d3d7589f1087470542ca1c763ef325775de5533ea"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bf4e616b5ade1557978d91897294f436d952b91ed5ef2cb9cd5765a03d3d42"}, + {file = "blake3-1.0.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:a911412d45c48364917875aad0fbaa9fcfa4b3b4fc9be8a21ccdcc83f0b15d93"}, + {file = "blake3-1.0.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9cb284412420f51f28378c65d5d218e8fe135e40940c185fd9dd3e5257f673d3"}, + {file = "blake3-1.0.1-cp313-cp313t-win32.whl", hash = "sha256:9b41e301a3bb962fa7d16b9b81b2f11f52af7dadd310aad9fb9e9317daaaf79a"}, + {file = "blake3-1.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:beb755df125c978d60bfbc8b35fbbf242aeb163ea7195f70541318b1f739f4fa"}, + {file = "blake3-1.0.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:7f395e608d1daf872b1a65e76b7e0a6fb825ddc1b25a954d777997f8bedaf285"}, + {file = "blake3-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3e717aceb2018f824a00fd0e1390698412ed34a51ecc234d99ef56111f4c1b3f"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb1186b5e5c4ae86b1f84e450dbe6a8d0eacad8019d17067da3c84885c6388e"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7287dd5b2218cd3417a4c6922b52540f8f80d6685cab15ef910b22ae11c84ce6"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95c43b3886264cb982d8bad7a4b19b902fdb64d614073448638932abe1f16e41"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2037e5f8b319003b61dfc28b2d6f59b6ad757448dd986e422642e60f5dedb970"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a663565cfd2abf4307e67e69a1b0f17e6b118471eac325365425aee1074e8f3"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56f73ea343a782fbc195424c6df265e38a183051ee72dd032560206b92a09b22"}, + {file = "blake3-1.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a6550ff4a3c4c6e85ec9bbe2082bd55cd47cc26e191419a0f8bc15dccc15b5f0"}, + {file = "blake3-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:87af8feb07126e3868d98a32da6a8639744aecb4e0dd8819a039aaa8687f078e"}, + {file = "blake3-1.0.1-cp38-cp38-win32.whl", hash = "sha256:77c68aaae459c67bb271271e114e08c5a240af509ee5925b30be3bc1ccd24ec9"}, + {file = "blake3-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:9a4f747db6d28f56939e1793fba3af3ddfe17d13819ddca60b758357a295ac84"}, + {file = "blake3-1.0.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e8a470f6f6111adbb89e054ba8f8d250369738ea07c0f4d7fca13c20c56e429d"}, + {file = "blake3-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6bf55e69e8bb4d26c72aff0da7e1703f48d6a3090eb1df4d646f77f419db2c3b"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d8f7eff3dd243f9c7e8c3351aa7cfc0934c7ccf404c5d868bc3778b4982071"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:088ee326dc1a650f9a128f3876ce2507467263fe6dcbbd21a67ce119a85ba93b"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a6b8f8b2fd288b1bf99aa80a1c9690b527bca853f560cf91d853447aec37cb4"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de0e747e9c9dcd6242bf771a6dc54fcd294c8c613eed0fb2bd3aa5cbfa57db11"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2bdaca3949d6b40a9dd1e910a6a70d1f178ddc09b85fb8b82e08a1948479f8"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae2282712c50d496037b0a694d5e1e31a7124d918a49c5feedef93146838ab0"}, + {file = "blake3-1.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d524f2e94b3251e262c4ace3c6ef0fd7637e3e9b54dd933f4d49aa38cf5f2c03"}, + {file = "blake3-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a625c9ecb89148c0c073ff0b3be14d17c5122879873783f8e85e8b1f18cc730a"}, + {file = "blake3-1.0.1-cp39-cp39-win32.whl", hash = "sha256:35214a680c990edc110de5093ede02a55e4379e8b1882b01e69e5b2a45f9091e"}, + {file = "blake3-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d1817014c7c7ab64b5bfa8db2e0a8b9cd44e43e50ea86d50af568525c5607be9"}, + {file = "blake3-1.0.1.tar.gz", hash = "sha256:a76c54e91ca3a28be760575726f8dc01572734023fe88bf8dfa76913fa48a943"}, +] + [[package]] name = "boto3" -version = "1.35.49" +version = "1.35.95" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.49-py3-none-any.whl", hash = "sha256:b660c649a27a6b47a34f6f858f5bd7c3b0a798a16dec8dda7cbebeee80fd1f60"}, - {file = "boto3-1.35.49.tar.gz", hash = "sha256:ddecb27f5699ca9f97711c52b6c0652c2e63bf6c2bfbc13b819b4f523b4d30ff"}, + {file = "boto3-1.35.95-py3-none-any.whl", hash = "sha256:c81223488607457dacb7829ee0c99803c664593b34a2b0f86c71d421e7c3469a"}, + {file = "boto3-1.35.95.tar.gz", hash = "sha256:d5671226819f6a78e31b1f37bd60f194afb8203254a543d06bdfb76de7d79236"}, ] [package.dependencies] -botocore = ">=1.35.49,<1.36.0" +botocore = ">=1.35.95,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -376,13 +490,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.49" +version = "1.35.95" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.49-py3-none-any.whl", hash = "sha256:aed4d3643afd702920792b68fbe712a8c3847993820d1048cd238a6469354da1"}, - {file = "botocore-1.35.49.tar.gz", hash = "sha256:07d0c1325fdbfa49a4a054413dbdeab0a6030449b2aa66099241af2dac48afd8"}, + {file = "botocore-1.35.95-py3-none-any.whl", hash = "sha256:a672406f748ad6a5b2fb7ea0d8394539eb4fda5332fc5373467d232c4bb27b12"}, + {file = "botocore-1.35.95.tar.gz", hash = "sha256:b03d2d7cc58a16aa96a7e8f21941b766e98abc6ea74f61a63de7dc26c03641d3"}, ] [package.dependencies] @@ -409,13 +523,13 @@ files = [ [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] @@ -499,127 +613,114 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -664,15 +765,29 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "colorful" +version = "0.5.6" +description = "Terminal string styling done right, in Python." +optional = true +python-versions = "*" +files = [ + {file = "colorful-0.5.6-py2.py3-none-any.whl", hash = "sha256:eab8c1c809f5025ad2b5238a50bd691e26850da8cac8f90d660ede6ea1af9f1e"}, + {file = "colorful-0.5.6.tar.gz", hash = "sha256:b56d5c01db1dac4898308ea889edcb113fbee3e6ec5df4bacffd61d5241b5b8d"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "compressed-tensors" -version = "0.6.0" +version = "0.8.1" description = "Library for utilization of compressed safetensors of neural network models" optional = true python-versions = "*" files = [ - {file = "compressed-tensors-0.6.0.tar.gz", hash = "sha256:639ca97afc852602be0d3666b236ad6a96880de45af87851f515047eff700927"}, - {file = "compressed_tensors-0.6.0-py3-none-any.whl", hash = "sha256:1be9c466e38b992b1d462e577f7e1b2bfad5d1aa0e25e9c95ab1ee458b9e92a2"}, + {file = "compressed-tensors-0.8.1.tar.gz", hash = "sha256:c8d04c0e6768c8286b0e8c38d63a7b89ae34d4b03f5de77cbe4f6f58222d4390"}, + {file = "compressed_tensors-0.8.1-py3-none-any.whl", hash = "sha256:5aa3b99642e5067a2c2e526be074948d2ae10bc5555d65b84bf60efcd612f445"}, ] [package.dependencies] @@ -686,73 +801,73 @@ dev = ["black (==22.12.0)", "flake8 (>=3.8.3)", "isort (==5.8.0)", "nbconvert (> [[package]] name = "coverage" -version = "7.6.4" +version = "7.6.10" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, - {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, - {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, - {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, - {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, - {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, - {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, - {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, - {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, - {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, - {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, - {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, - {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, - {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, - {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, - {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, + {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, + {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"}, + {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"}, + {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"}, + {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"}, + {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"}, + {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"}, + {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"}, + {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"}, + {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"}, + {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"}, + {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"}, + {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"}, + {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"}, + {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"}, + {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"}, + {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"}, + {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"}, + {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"}, + {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"}, + {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"}, + {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"}, + {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"}, + {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"}, + {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"}, + {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"}, ] [package.dependencies] @@ -810,48 +925,6 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] -[[package]] -name = "datasets" -version = "2.14.4" -description = "HuggingFace community-driven open-source library of datasets" -optional = true -python-versions = ">=3.8.0" -files = [ - {file = "datasets-2.14.4-py3-none-any.whl", hash = "sha256:29336bd316a7d827ccd4da2236596279b20ca2ac78f64c04c9483da7cbc2459b"}, - {file = "datasets-2.14.4.tar.gz", hash = "sha256:ef29c2b5841de488cd343cfc26ab979bff77efa4d2285af51f1ad7db5c46a83b"}, -] - -[package.dependencies] -aiohttp = "*" -dill = ">=0.3.0,<0.3.8" -fsspec = {version = ">=2021.11.1", extras = ["http"]} -huggingface-hub = ">=0.14.0,<1.0.0" -multiprocess = "*" -numpy = ">=1.17" -packaging = "*" -pandas = "*" -pyarrow = ">=8.0.0" -pyyaml = ">=5.1" -requests = ">=2.19.0" -tqdm = ">=4.62.1" -xxhash = "*" - -[package.extras] -apache-beam = ["apache-beam (>=2.26.0,<2.44.0)"] -audio = ["librosa", "soundfile (>=0.12.1)"] -benchmarks = ["tensorflow (==2.12.0)", "torch (==2.0.1)", "transformers (==4.30.1)"] -dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0,<2.44.0)", "black (>=23.1,<24.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "pyyaml (>=5.3.1)", "rarfile (>=4.0)", "ruff (>=0.0.241)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy (<2.0.0)", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "transformers", "zstandard"] -docs = ["s3fs", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos", "torch", "transformers"] -jax = ["jax (>=0.2.8,!=0.3.2,<=0.3.25)", "jaxlib (>=0.1.65,<=0.3.25)"] -metrics-tests = ["Werkzeug (>=1.0.1)", "accelerate", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "requests-file (>=1.5.1)", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "spacy (>=3.0.0)", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "typer (<0.5.0)"] -quality = ["black (>=23.1,<24.0)", "pyyaml (>=5.3.1)", "ruff (>=0.0.241)"] -s3 = ["s3fs"] -tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos"] -tensorflow-gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"] -tests = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0,<2.44.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy (<2.0.0)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "transformers", "zstandard"] -torch = ["torch"] -vision = ["Pillow (>=6.2.1)"] - [[package]] name = "deprecation" version = "2.1.0" @@ -866,19 +939,38 @@ files = [ [package.dependencies] packaging = "*" +[[package]] +name = "depyf" +version = "0.18.0" +description = "Decompile python functions, from bytecode to source code!" +optional = true +python-versions = ">=3.7" +files = [ + {file = "depyf-0.18.0-py3-none-any.whl", hash = "sha256:007294d5bac19a38a0767d747be0f49b9ffdcea0394a822644142df22b33a3e1"}, + {file = "depyf-0.18.0.tar.gz", hash = "sha256:b99f0c383be949ae45d5d606fe444c71f375b55a57b8d6b20e7856670d52130d"}, +] + +[package.dependencies] +astor = "*" +dill = "*" + +[package.extras] +dev = ["autopep8", "flake8", "pytest"] + [[package]] name = "dill" -version = "0.3.7" +version = "0.3.9" description = "serialize all of Python" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "diskcache" @@ -891,6 +983,17 @@ files = [ {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, ] +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = true +python-versions = "*" +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + [[package]] name = "distro" version = "1.9.0" @@ -940,13 +1043,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.5" +version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"}, - {file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"}, + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, ] [package.dependencies] @@ -1077,18 +1180,15 @@ files = [ [[package]] name = "fsspec" -version = "2024.10.0" +version = "2024.12.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871"}, - {file = "fsspec-2024.10.0.tar.gz", hash = "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493"}, + {file = "fsspec-2024.12.0-py3-none-any.whl", hash = "sha256:b520aed47ad9804237ff878b504267a3b0b441e97508bd6d2d8774e3db85cee2"}, + {file = "fsspec-2024.12.0.tar.gz", hash = "sha256:670700c977ed2fb51e0d9f9253177ed20cbde4a3e5c0283cc5385b5870c8533f"}, ] -[package.dependencies] -aiohttp = {version = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1", optional = true, markers = "extra == \"http\""} - [package.extras] abfs = ["adlfs"] adl = ["adlfs"] @@ -1135,13 +1235,13 @@ tqdm = ">=4.27" [[package]] name = "google-api-core" -version = "2.21.0" +version = "2.24.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google_api_core-2.21.0-py3-none-any.whl", hash = "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d"}, - {file = "google_api_core-2.21.0.tar.gz", hash = "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81"}, + {file = "google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9"}, + {file = "google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf"}, ] [package.dependencies] @@ -1159,13 +1259,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.35.0" +version = "2.37.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google_auth-2.35.0-py2.py3-none-any.whl", hash = "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f"}, - {file = "google_auth-2.35.0.tar.gz", hash = "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a"}, + {file = "google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0"}, + {file = "google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00"}, ] [package.dependencies] @@ -1176,6 +1276,7 @@ rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] @@ -1200,13 +1301,13 @@ grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-storage" -version = "2.18.2" +version = "2.19.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google_cloud_storage-2.18.2-py2.py3-none-any.whl", hash = "sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166"}, - {file = "google_cloud_storage-2.18.2.tar.gz", hash = "sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99"}, + {file = "google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba"}, + {file = "google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"}, ] [package.dependencies] @@ -1280,13 +1381,13 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.65.0" +version = "1.66.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, - {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, + {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, + {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, ] [package.dependencies] @@ -1314,70 +1415,70 @@ testing = ["protobuf (>=4.21.9)"] [[package]] name = "grpcio" -version = "1.67.0" +version = "1.69.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.67.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:bd79929b3bb96b54df1296cd3bf4d2b770bd1df6c2bdf549b49bab286b925cdc"}, - {file = "grpcio-1.67.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:16724ffc956ea42967f5758c2f043faef43cb7e48a51948ab593570570d1e68b"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:2b7183c80b602b0ad816315d66f2fb7887614ead950416d60913a9a71c12560d"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efe32b45dd6d118f5ea2e5deaed417d8a14976325c93812dd831908522b402c9"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe89295219b9c9e47780a0f1c75ca44211e706d1c598242249fe717af3385ec8"}, - {file = "grpcio-1.67.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa8d025fae1595a207b4e47c2e087cb88d47008494db258ac561c00877d4c8f8"}, - {file = "grpcio-1.67.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f95e15db43e75a534420e04822df91f645664bf4ad21dfaad7d51773c80e6bb4"}, - {file = "grpcio-1.67.0-cp310-cp310-win32.whl", hash = "sha256:a6b9a5c18863fd4b6624a42e2712103fb0f57799a3b29651c0e5b8119a519d65"}, - {file = "grpcio-1.67.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6eb68493a05d38b426604e1dc93bfc0137c4157f7ab4fac5771fd9a104bbaa6"}, - {file = "grpcio-1.67.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:e91d154689639932305b6ea6f45c6e46bb51ecc8ea77c10ef25aa77f75443ad4"}, - {file = "grpcio-1.67.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb204a742997277da678611a809a8409657b1398aaeebf73b3d9563b7d154c13"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:ae6de510f670137e755eb2a74b04d1041e7210af2444103c8c95f193340d17ee"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74b900566bdf68241118f2918d312d3bf554b2ce0b12b90178091ea7d0a17b3d"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4e95e43447a02aa603abcc6b5e727d093d161a869c83b073f50b9390ecf0fa8"}, - {file = "grpcio-1.67.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0bb94e66cd8f0baf29bd3184b6aa09aeb1a660f9ec3d85da615c5003154bc2bf"}, - {file = "grpcio-1.67.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:82e5bd4b67b17c8c597273663794a6a46a45e44165b960517fe6d8a2f7f16d23"}, - {file = "grpcio-1.67.0-cp311-cp311-win32.whl", hash = "sha256:7fc1d2b9fd549264ae585026b266ac2db53735510a207381be509c315b4af4e8"}, - {file = "grpcio-1.67.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac11ecb34a86b831239cc38245403a8de25037b448464f95c3315819e7519772"}, - {file = "grpcio-1.67.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:227316b5631260e0bef8a3ce04fa7db4cc81756fea1258b007950b6efc90c05d"}, - {file = "grpcio-1.67.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d90cfdafcf4b45a7a076e3e2a58e7bc3d59c698c4f6470b0bb13a4d869cf2273"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:77196216d5dd6f99af1c51e235af2dd339159f657280e65ce7e12c1a8feffd1d"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15c05a26a0f7047f720da41dc49406b395c1470eef44ff7e2c506a47ac2c0591"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3840994689cc8cbb73d60485c594424ad8adb56c71a30d8948d6453083624b52"}, - {file = "grpcio-1.67.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5a1e03c3102b6451028d5dc9f8591131d6ab3c8a0e023d94c28cb930ed4b5f81"}, - {file = "grpcio-1.67.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:682968427a63d898759474e3b3178d42546e878fdce034fd7474ef75143b64e3"}, - {file = "grpcio-1.67.0-cp312-cp312-win32.whl", hash = "sha256:d01793653248f49cf47e5695e0a79805b1d9d4eacef85b310118ba1dfcd1b955"}, - {file = "grpcio-1.67.0-cp312-cp312-win_amd64.whl", hash = "sha256:985b2686f786f3e20326c4367eebdaed3e7aa65848260ff0c6644f817042cb15"}, - {file = "grpcio-1.67.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:8c9a35b8bc50db35ab8e3e02a4f2a35cfba46c8705c3911c34ce343bd777813a"}, - {file = "grpcio-1.67.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:42199e704095b62688998c2d84c89e59a26a7d5d32eed86d43dc90e7a3bd04aa"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:c4c425f440fb81f8d0237c07b9322fc0fb6ee2b29fbef5f62a322ff8fcce240d"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:323741b6699cd2b04a71cb38f502db98f90532e8a40cb675393d248126a268af"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:662c8e105c5e5cee0317d500eb186ed7a93229586e431c1bf0c9236c2407352c"}, - {file = "grpcio-1.67.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f6bd2ab135c64a4d1e9e44679a616c9bc944547357c830fafea5c3caa3de5153"}, - {file = "grpcio-1.67.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:2f55c1e0e2ae9bdd23b3c63459ee4c06d223b68aeb1961d83c48fb63dc29bc03"}, - {file = "grpcio-1.67.0-cp313-cp313-win32.whl", hash = "sha256:fd6bc27861e460fe28e94226e3673d46e294ca4673d46b224428d197c5935e69"}, - {file = "grpcio-1.67.0-cp313-cp313-win_amd64.whl", hash = "sha256:cf51d28063338608cd8d3cd64677e922134837902b70ce00dad7f116e3998210"}, - {file = "grpcio-1.67.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:7f200aca719c1c5dc72ab68be3479b9dafccdf03df530d137632c534bb6f1ee3"}, - {file = "grpcio-1.67.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0892dd200ece4822d72dd0952f7112c542a487fc48fe77568deaaa399c1e717d"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f4d613fbf868b2e2444f490d18af472ccb47660ea3df52f068c9c8801e1f3e85"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c69bf11894cad9da00047f46584d5758d6ebc9b5950c0dc96fec7e0bce5cde9"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9bca3ca0c5e74dea44bf57d27e15a3a3996ce7e5780d61b7c72386356d231db"}, - {file = "grpcio-1.67.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:014dfc020e28a0d9be7e93a91f85ff9f4a87158b7df9952fe23cc42d29d31e1e"}, - {file = "grpcio-1.67.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d4ea4509d42c6797539e9ec7496c15473177ce9abc89bc5c71e7abe50fc25737"}, - {file = "grpcio-1.67.0-cp38-cp38-win32.whl", hash = "sha256:9d75641a2fca9ae1ae86454fd25d4c298ea8cc195dbc962852234d54a07060ad"}, - {file = "grpcio-1.67.0-cp38-cp38-win_amd64.whl", hash = "sha256:cff8e54d6a463883cda2fab94d2062aad2f5edd7f06ae3ed030f2a74756db365"}, - {file = "grpcio-1.67.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:62492bd534979e6d7127b8a6b29093161a742dee3875873e01964049d5250a74"}, - {file = "grpcio-1.67.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eef1dce9d1a46119fd09f9a992cf6ab9d9178b696382439446ca5f399d7b96fe"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f623c57a5321461c84498a99dddf9d13dac0e40ee056d884d6ec4ebcab647a78"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54d16383044e681f8beb50f905249e4e7261dd169d4aaf6e52eab67b01cbbbe2"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2a44e572fb762c668e4812156b81835f7aba8a721b027e2d4bb29fb50ff4d33"}, - {file = "grpcio-1.67.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:391df8b0faac84d42f5b8dfc65f5152c48ed914e13c522fd05f2aca211f8bfad"}, - {file = "grpcio-1.67.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfd9306511fdfc623a1ba1dc3bc07fbd24e6cfbe3c28b4d1e05177baa2f99617"}, - {file = "grpcio-1.67.0-cp39-cp39-win32.whl", hash = "sha256:30d47dbacfd20cbd0c8be9bfa52fdb833b395d4ec32fe5cff7220afc05d08571"}, - {file = "grpcio-1.67.0-cp39-cp39-win_amd64.whl", hash = "sha256:f55f077685f61f0fbd06ea355142b71e47e4a26d2d678b3ba27248abfe67163a"}, - {file = "grpcio-1.67.0.tar.gz", hash = "sha256:e090b2553e0da1c875449c8e75073dd4415dd71c9bde6a406240fdf4c0ee467c"}, + {file = "grpcio-1.69.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:2060ca95a8db295ae828d0fc1c7f38fb26ccd5edf9aa51a0f44251f5da332e97"}, + {file = "grpcio-1.69.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2e52e107261fd8fa8fa457fe44bfadb904ae869d87c1280bf60f93ecd3e79278"}, + {file = "grpcio-1.69.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:316463c0832d5fcdb5e35ff2826d9aa3f26758d29cdfb59a368c1d6c39615a11"}, + {file = "grpcio-1.69.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26c9a9c4ac917efab4704b18eed9082ed3b6ad19595f047e8173b5182fec0d5e"}, + {file = "grpcio-1.69.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90b3646ced2eae3a0599658eeccc5ba7f303bf51b82514c50715bdd2b109e5ec"}, + {file = "grpcio-1.69.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3b75aea7c6cb91b341c85e7c1d9db1e09e1dd630b0717f836be94971e015031e"}, + {file = "grpcio-1.69.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5cfd14175f9db33d4b74d63de87c64bb0ee29ce475ce3c00c01ad2a3dc2a9e51"}, + {file = "grpcio-1.69.0-cp310-cp310-win32.whl", hash = "sha256:9031069d36cb949205293cf0e243abd5e64d6c93e01b078c37921493a41b72dc"}, + {file = "grpcio-1.69.0-cp310-cp310-win_amd64.whl", hash = "sha256:cc89b6c29f3dccbe12d7a3b3f1b3999db4882ae076c1c1f6df231d55dbd767a5"}, + {file = "grpcio-1.69.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:8de1b192c29b8ce45ee26a700044717bcbbd21c697fa1124d440548964328561"}, + {file = "grpcio-1.69.0-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:7e76accf38808f5c5c752b0ab3fd919eb14ff8fafb8db520ad1cc12afff74de6"}, + {file = "grpcio-1.69.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:d5658c3c2660417d82db51e168b277e0ff036d0b0f859fa7576c0ffd2aec1442"}, + {file = "grpcio-1.69.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5494d0e52bf77a2f7eb17c6da662886ca0a731e56c1c85b93505bece8dc6cf4c"}, + {file = "grpcio-1.69.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ed866f9edb574fd9be71bf64c954ce1b88fc93b2a4cbf94af221e9426eb14d6"}, + {file = "grpcio-1.69.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c5ba38aeac7a2fe353615c6b4213d1fbb3a3c34f86b4aaa8be08baaaee8cc56d"}, + {file = "grpcio-1.69.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f79e05f5bbf551c4057c227d1b041ace0e78462ac8128e2ad39ec58a382536d2"}, + {file = "grpcio-1.69.0-cp311-cp311-win32.whl", hash = "sha256:bf1f8be0da3fcdb2c1e9f374f3c2d043d606d69f425cd685110dd6d0d2d61258"}, + {file = "grpcio-1.69.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb9302afc3a0e4ba0b225cd651ef8e478bf0070cf11a529175caecd5ea2474e7"}, + {file = "grpcio-1.69.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:fc18a4de8c33491ad6f70022af5c460b39611e39578a4d84de0fe92f12d5d47b"}, + {file = "grpcio-1.69.0-cp312-cp312-macosx_10_14_universal2.whl", hash = "sha256:0f0270bd9ffbff6961fe1da487bdcd594407ad390cc7960e738725d4807b18c4"}, + {file = "grpcio-1.69.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:dc48f99cc05e0698e689b51a05933253c69a8c8559a47f605cff83801b03af0e"}, + {file = "grpcio-1.69.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e925954b18d41aeb5ae250262116d0970893b38232689c4240024e4333ac084"}, + {file = "grpcio-1.69.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d222569273720366f68a99cb62e6194681eb763ee1d3b1005840678d4884f9"}, + {file = "grpcio-1.69.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b62b0f41e6e01a3e5082000b612064c87c93a49b05f7602fe1b7aa9fd5171a1d"}, + {file = "grpcio-1.69.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:db6f9fd2578dbe37db4b2994c94a1d9c93552ed77dca80e1657bb8a05b898b55"}, + {file = "grpcio-1.69.0-cp312-cp312-win32.whl", hash = "sha256:b192b81076073ed46f4b4dd612b8897d9a1e39d4eabd822e5da7b38497ed77e1"}, + {file = "grpcio-1.69.0-cp312-cp312-win_amd64.whl", hash = "sha256:1227ff7836f7b3a4ab04e5754f1d001fa52a730685d3dc894ed8bc262cc96c01"}, + {file = "grpcio-1.69.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:a78a06911d4081a24a1761d16215a08e9b6d4d29cdbb7e427e6c7e17b06bcc5d"}, + {file = "grpcio-1.69.0-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:dc5a351927d605b2721cbb46158e431dd49ce66ffbacb03e709dc07a491dde35"}, + {file = "grpcio-1.69.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:3629d8a8185f5139869a6a17865d03113a260e311e78fbe313f1a71603617589"}, + {file = "grpcio-1.69.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9a281878feeb9ae26db0622a19add03922a028d4db684658f16d546601a4870"}, + {file = "grpcio-1.69.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cc614e895177ab7e4b70f154d1a7c97e152577ea101d76026d132b7aaba003b"}, + {file = "grpcio-1.69.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:1ee76cd7e2e49cf9264f6812d8c9ac1b85dda0eaea063af07292400f9191750e"}, + {file = "grpcio-1.69.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:0470fa911c503af59ec8bc4c82b371ee4303ececbbdc055f55ce48e38b20fd67"}, + {file = "grpcio-1.69.0-cp313-cp313-win32.whl", hash = "sha256:b650f34aceac8b2d08a4c8d7dc3e8a593f4d9e26d86751ebf74ebf5107d927de"}, + {file = "grpcio-1.69.0-cp313-cp313-win_amd64.whl", hash = "sha256:028337786f11fecb5d7b7fa660475a06aabf7e5e52b5ac2df47414878c0ce7ea"}, + {file = "grpcio-1.69.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:b7f693db593d6bf285e015d5538bf1c86cf9c60ed30b6f7da04a00ed052fe2f3"}, + {file = "grpcio-1.69.0-cp38-cp38-macosx_10_14_universal2.whl", hash = "sha256:8b94e83f66dbf6fd642415faca0608590bc5e8d30e2c012b31d7d1b91b1de2fd"}, + {file = "grpcio-1.69.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:b634851b92c090763dde61df0868c730376cdb73a91bcc821af56ae043b09596"}, + {file = "grpcio-1.69.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf5f680d3ed08c15330d7830d06bc65f58ca40c9999309517fd62880d70cb06e"}, + {file = "grpcio-1.69.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:200e48a6e7b00f804cf00a1c26292a5baa96507c7749e70a3ec10ca1a288936e"}, + {file = "grpcio-1.69.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:45a4704339b6e5b24b0e136dea9ad3815a94f30eb4f1e1d44c4ac484ef11d8dd"}, + {file = "grpcio-1.69.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85d347cb8237751b23539981dbd2d9d8f6e9ff90082b427b13022b948eb6347a"}, + {file = "grpcio-1.69.0-cp38-cp38-win32.whl", hash = "sha256:60e5de105dc02832dc8f120056306d0ef80932bcf1c0e2b4ca3b676de6dc6505"}, + {file = "grpcio-1.69.0-cp38-cp38-win_amd64.whl", hash = "sha256:282f47d0928e40f25d007f24eb8fa051cb22551e3c74b8248bc9f9bea9c35fe0"}, + {file = "grpcio-1.69.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:dd034d68a2905464c49479b0c209c773737a4245d616234c79c975c7c90eca03"}, + {file = "grpcio-1.69.0-cp39-cp39-macosx_10_14_universal2.whl", hash = "sha256:01f834732c22a130bdf3dc154d1053bdbc887eb3ccb7f3e6285cfbfc33d9d5cc"}, + {file = "grpcio-1.69.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:a7f4ed0dcf202a70fe661329f8874bc3775c14bb3911d020d07c82c766ce0eb1"}, + {file = "grpcio-1.69.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd7ea241b10bc5f0bb0f82c0d7896822b7ed122b3ab35c9851b440c1ccf81588"}, + {file = "grpcio-1.69.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f03dc9b4da4c0dc8a1db7a5420f575251d7319b7a839004d8916257ddbe4816"}, + {file = "grpcio-1.69.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ca71d73a270dff052fe4edf74fef142d6ddd1f84175d9ac4a14b7280572ac519"}, + {file = "grpcio-1.69.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ccbed100dc43704e94ccff9e07680b540d64e4cc89213ab2832b51b4f68a520"}, + {file = "grpcio-1.69.0-cp39-cp39-win32.whl", hash = "sha256:1514341def9c6ec4b7f0b9628be95f620f9d4b99331b7ef0a1845fd33d9b579c"}, + {file = "grpcio-1.69.0-cp39-cp39-win_amd64.whl", hash = "sha256:c1fea55d26d647346acb0069b08dca70984101f2dc95066e003019207212e303"}, + {file = "grpcio-1.69.0.tar.gz", hash = "sha256:936fa44241b5379c5afc344e1260d467bee495747eaf478de825bab2791da6f5"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.67.0)"] +protobuf = ["grpcio-tools (>=1.69.0)"] [[package]] name = "h11" @@ -1392,77 +1493,47 @@ files = [ [[package]] name = "hf-transfer" -version = "0.1.8" +version = "0.1.9" description = "Speed up file transfers with the Hugging Face Hub." optional = false python-versions = ">=3.7" files = [ - {file = "hf_transfer-0.1.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:70858f9e94286738ed300484a45beb5cfee6a7ddac4c5886f9c6fce7823ac5ab"}, - {file = "hf_transfer-0.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38adc73f0a8526319d90f7cc5dc2d5e4bb66f487a513d94b98aa6725be732e4a"}, - {file = "hf_transfer-0.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d2f0c08198d8d899fe9d66e86aee2dd844bd7ce33888f261373fcec81d2a54"}, - {file = "hf_transfer-0.1.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1de2a4ef36f9e60b3d3bec00193c0aafd75771709f2ca51b9b162373f5af3d32"}, - {file = "hf_transfer-0.1.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e319269e3606a5ff2979296841766649ac73598a4a8eee2a968f86c8071fea5a"}, - {file = "hf_transfer-0.1.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f6026cf3be6a53ea42f92172f60c1c0675baaa9073f865e671b661dde5fd157"}, - {file = "hf_transfer-0.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f865c33ada5bd3650c2b46e59979f2d7755c3f517f8d0facc78576a0c7d26406"}, - {file = "hf_transfer-0.1.8-cp310-none-win32.whl", hash = "sha256:2054730e8d8ed21917c64be7199e06424b2bd08df1c43a72766afaed7992f2d3"}, - {file = "hf_transfer-0.1.8-cp310-none-win_amd64.whl", hash = "sha256:2b4f1a9446ba31170b5b1eca4e916504d18378a6b5fe959896bdac8a736a5ecb"}, - {file = "hf_transfer-0.1.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e27c15fcc5869ad7e52bbc0bdec6106b288d1c463f8d2da92f28615a3b181361"}, - {file = "hf_transfer-0.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:871a0032d011ebc6409a73a8406b98b84ff2cd3ed7d9e1af8cdf4d660b9fab9b"}, - {file = "hf_transfer-0.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:686fa756e1e0214bb6327d33c66732c52274d94a8460beb50604ad988b391cf6"}, - {file = "hf_transfer-0.1.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36a03b1b2911b0cf15b1b9d971a34b32dadcc4f2fd979aaff5979d6ce4017c34"}, - {file = "hf_transfer-0.1.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:079db90c81f41f4cf3227dfaaa855a9b8e9aef45bc7c2be29ce7232cd83ff881"}, - {file = "hf_transfer-0.1.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac08a4524127fdd14c234d4bcbe49d1c498acf5335c781714823179bcc8dc039"}, - {file = "hf_transfer-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:837432e73cb17274a6782b6216e8ce058aa325a475dc44a5a6a753d48b86d18a"}, - {file = "hf_transfer-0.1.8-cp311-none-win32.whl", hash = "sha256:b180f9823dde35aba9bc0f1d0c04ac8a873baebd3732a7ffe4f11940abc7df0d"}, - {file = "hf_transfer-0.1.8-cp311-none-win_amd64.whl", hash = "sha256:37907d2135cebcf8b6d419bb575148d89c224f16b69357f027bd29d0e85c6529"}, - {file = "hf_transfer-0.1.8-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:baf948f4f493949309cbe60529620b9b0aef854a22b6e526753364acc57c09b6"}, - {file = "hf_transfer-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bce5c8bdefa478c5d5eaa646cc4ce1df5cfe764d98572ad0c6b8773e98d49f6"}, - {file = "hf_transfer-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d6f8a1a86128d651a3799e1267c343d60f81f2c565d7c5416eb8e674e4cf0e"}, - {file = "hf_transfer-0.1.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f79fd1b0c2ed93efb4c5f684118d7a762ecdd218e170df8208c4e13d3dcd4959"}, - {file = "hf_transfer-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:414df35692670683bf5623498ef9d88a8df5d77e9516515da6e2b34d1054c11f"}, - {file = "hf_transfer-0.1.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c9798d5f951f66b96d40a7a53910260cb5874fda56cf5944dddb7c571f37ec3"}, - {file = "hf_transfer-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:060c661691f85a61392e57579c80eb64b5ee277434e81fb582f605c1c8ff05d5"}, - {file = "hf_transfer-0.1.8-cp312-none-win32.whl", hash = "sha256:f7840e32379820c3e1571a480238e05ea043e970c99d2e999578004a2eb17788"}, - {file = "hf_transfer-0.1.8-cp312-none-win_amd64.whl", hash = "sha256:9a3204ec423cc5e659872e8179f8704ad9ce2abb1e6a991f8838aedf1dc07830"}, - {file = "hf_transfer-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09949e86ad63ee139e463fd0dfaf401515ae70445854199f61d545514c65f744"}, - {file = "hf_transfer-0.1.8-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf1a74552845b93ea972e6e7131ef54e56056aa54137e93a40faf3fbcb2442ff"}, - {file = "hf_transfer-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959bcb3afb4ee6f2a07031a947dba98ec0b64c001bc914fbd8fc32e13a287162"}, - {file = "hf_transfer-0.1.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e01eecdb8162bd61dab9090fbd9f8034dd8b5755ef727a21ca8a057f80cb91ee"}, - {file = "hf_transfer-0.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50650a38e9d31f5ad8f010e4598bf304ecd99c17162e7d93f67e031571b864ee"}, - {file = "hf_transfer-0.1.8-cp37-none-win32.whl", hash = "sha256:e29b9d1d378138f2f4eae0e93ca94af3b5d45f4532eef69f1ab97fe06f9c9d9e"}, - {file = "hf_transfer-0.1.8-cp37-none-win_amd64.whl", hash = "sha256:cfd6cef43ae883103117a371f8ebae4e7f9637bc6fb480f1be5568e2fe22a8a7"}, - {file = "hf_transfer-0.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92a68f7a0043cca8a0de4decc760dca177530944cbab502afac503bd1b2fa01a"}, - {file = "hf_transfer-0.1.8-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e3138e408179f80a5480598e32f8e1abb564915cbde4d3bc8da52811c75dc3ea"}, - {file = "hf_transfer-0.1.8-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4544d148930ad34442d43b8fa911c8479c04a95b858b1d1f91e0b7da77082fad"}, - {file = "hf_transfer-0.1.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a851794b9f029965664f8c3002c957fccf21685e9397ceb4f9f19c986dee8ad3"}, - {file = "hf_transfer-0.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:791aaf87c5319ac83edb6ab2994b3db19924c49d6ff667dd3d8a610b455ff70a"}, - {file = "hf_transfer-0.1.8-cp38-none-win32.whl", hash = "sha256:8f71e5d35d3a3160dcca12fdcc8119033aeacaa6a32838a7ad9f9cb1008bbe58"}, - {file = "hf_transfer-0.1.8-cp38-none-win_amd64.whl", hash = "sha256:543287b4ceb1e25501580b99690f7f0df9d3631d29306f37cbd97e918c732944"}, - {file = "hf_transfer-0.1.8-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7ce02a18bd0bb2343e707ac85b68c946bc37623ee24150c69158f6b2b2c7a98f"}, - {file = "hf_transfer-0.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64d7f8dbd64ba183ed1df75d47c84e075ff666ceaa335bff1de16b09eaac5b80"}, - {file = "hf_transfer-0.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e7858694e11419ae27e542fb8fc0d0e54d46ff7768fe73bc359d70b8f5aa578"}, - {file = "hf_transfer-0.1.8-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed116cd9d1edfa32c0136d7cb8e5f1afd2b32df43c49085d428f108fc8e1c8f"}, - {file = "hf_transfer-0.1.8-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e385d0da9c6b3472ab29285d2d46c9f9903205b8d108f88a82f3f85aafae0ab"}, - {file = "hf_transfer-0.1.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98f75fa4b86ef15433cd907807ac77d1fb39d7e7b790bfd39c7ae9c385bf0200"}, - {file = "hf_transfer-0.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a63ad947d2901425ac0a3ed70c3696dfde27fadb0482ed763bdd5cc946b278"}, - {file = "hf_transfer-0.1.8-cp39-none-win32.whl", hash = "sha256:3e74096915813ae842ea6a5bdf10c0fef960aa51a35a560955b3e61cdfe3db57"}, - {file = "hf_transfer-0.1.8-cp39-none-win_amd64.whl", hash = "sha256:05ea16307bf4a5eb097cbc6e5057e4eb5e080a138af23ef639fd38857723c288"}, - {file = "hf_transfer-0.1.8-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:928ff036c3e98e10dcfbdb4fcdfc4592d37a5cc8e365a7ba8dfd4337e849d675"}, - {file = "hf_transfer-0.1.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d49ba3ce67035f460ae1924fe2feafec155cb535eec7f31ed5109c19064cd294"}, - {file = "hf_transfer-0.1.8-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b01f5872c62cfee3ec9ca5c738818296f69f8adf84b4d8d15f2a5601d9dda339"}, - {file = "hf_transfer-0.1.8-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:659d4212d50847a5165666bf43d67727679b4f694ef9c413613cc27093136527"}, - {file = "hf_transfer-0.1.8.tar.gz", hash = "sha256:26d229468152e7a3ec12664cac86b8c2800695fd85f9c9a96677a775cc04f0b3"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:6e94e8822da79573c9b6ae4d6b2f847c59a7a06c5327d7db20751b68538dc4f6"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ebc4ab9023414880c8b1d3c38174d1c9989eb5022d37e814fa91a3060123eb0"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8674026f21ed369aa2a0a4b46000aca850fc44cd2b54af33a172ce5325b4fc82"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a736dfbb2c84f5a2c975478ad200c0c8bfcb58a25a35db402678fb87ce17fa4"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:504b8427fd785dd8546d53b9fafe6e436bd7a3adf76b9dce556507650a7b4567"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c7fc1b85f4d0f76e452765d7648c9f4bfd0aedb9ced2ae1ebfece2d8cfaf8e2"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d991376f0eac70a60f0cbc95602aa708a6f7c8617f28b4945c1431d67b8e3c8"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e6ac4eddcd99575ed3735ed911ddf9d1697e2bd13aa3f0ad7e3904dd4863842e"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:57fd9880da1ee0f47250f735f791fab788f0aa1ee36afc49f761349869c8b4d9"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:5d561f0520f493c66b016d99ceabe69c23289aa90be38dd802d2aef279f15751"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a5b366d34cd449fe9b20ef25941e6eef0460a2f74e7389f02e673e1f88ebd538"}, + {file = "hf_transfer-0.1.9-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e66acf91df4a8b72f60223059df3003062a5ae111757187ed1a06750a30e911b"}, + {file = "hf_transfer-0.1.9-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:8669dbcc7a3e2e8d61d42cd24da9c50d57770bd74b445c65123291ca842a7e7a"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fd0167c4407a3bc4cdd0307e65ada2294ec04f1813d8a69a5243e379b22e9d8"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee8b10afedcb75f71091bcc197c526a6ebf5c58bbbadb34fdeee6160f55f619f"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5828057e313de59300dd1abb489444bc452efe3f479d3c55b31a8f680936ba42"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc6bd19e1cc177c66bdef15ef8636ad3bde79d5a4f608c158021153b4573509d"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdca9bfb89e6f8f281890cc61a8aff2d3cecaff7e1a4d275574d96ca70098557"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:89a23f58b7b7effbc047b8ca286f131b17728c99a9f972723323003ffd1bb916"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:dc7fff1345980d6c0ebb92c811d24afa4b98b3e07ed070c8e38cc91fd80478c5"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a6bd16c667ebe89a069ca163060127a794fa3a3525292c900b8c8cc47985b0d"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d2fde99d502093ade3ab1b53f80da18480e9902aa960dab7f74fb1b9e5bc5746"}, + {file = "hf_transfer-0.1.9-cp38-abi3-win32.whl", hash = "sha256:435cc3cdc8524ce57b074032b8fd76eed70a4224d2091232fa6a8cef8fd6803e"}, + {file = "hf_transfer-0.1.9-cp38-abi3-win_amd64.whl", hash = "sha256:16f208fc678911c37e11aa7b586bc66a37d02e636208f18b6bc53d29b5df40ad"}, + {file = "hf_transfer-0.1.9.tar.gz", hash = "sha256:035572865dab29d17e783fbf1e84cf1cb24f3fcf8f1b17db1cfc7fdf139f02bf"}, ] [[package]] name = "httpcore" -version = "1.0.6" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -1662,13 +1733,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [package.dependencies] @@ -1679,84 +1750,87 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.6.1" +version = "0.8.2" description = "Fast iterable JSON parser." optional = true python-versions = ">=3.8" files = [ - {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, - {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e02f7a27f2bcc15b7d455c9df05df8ffffcc596a2a541eeda9a3110326e7a3"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed69a7971d67b08f152c17c638f0e8c2aa207e9dd3a5fcd3cba294d39b5a8d2d"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2019d966e98f7c6df24b3b8363998575f47d26471bfb14aade37630fae836a1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36c0b51a285b68311e207a76c385650322734c8717d16c2eb8af75c9d69506e7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:220e0963b4fb507c525c8f58cde3da6b1be0bfddb7ffd6798fb8f2531226cdb1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa25c7a9bf7875a141182b9c95aed487add635da01942ef7ca726e42a0c09058"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e90552109ca8ccd07f47ca99c8a1509ced93920d271bb81780a973279974c5ab"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:67723a011964971864e0b484b0ecfee6a14de1533cff7ffd71189e92103b38a8"}, - {file = "jiter-0.6.1-cp310-none-win32.whl", hash = "sha256:33af2b7d2bf310fdfec2da0177eab2fedab8679d1538d5b86a633ebfbbac4edd"}, - {file = "jiter-0.6.1-cp310-none-win_amd64.whl", hash = "sha256:7cea41c4c673353799906d940eee8f2d8fd1d9561d734aa921ae0f75cb9732f4"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b03c24e7da7e75b170c7b2b172d9c5e463aa4b5c95696a368d52c295b3f6847f"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:47fee1be677b25d0ef79d687e238dc6ac91a8e553e1a68d0839f38c69e0ee491"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f0d2f6e01a8a0fb0eab6d0e469058dab2be46ff3139ed2d1543475b5a1d8e7"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b809e39e342c346df454b29bfcc7bca3d957f5d7b60e33dae42b0e5ec13e027"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e9ac7c2f092f231f5620bef23ce2e530bd218fc046098747cc390b21b8738a7a"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e51a2d80d5fe0ffb10ed2c82b6004458be4a3f2b9c7d09ed85baa2fbf033f54b"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3343d4706a2b7140e8bd49b6c8b0a82abf9194b3f0f5925a78fc69359f8fc33c"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82521000d18c71e41c96960cb36e915a357bc83d63a8bed63154b89d95d05ad1"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c843e7c1633470708a3987e8ce617ee2979ee18542d6eb25ae92861af3f1d62"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a2e861658c3fe849efc39b06ebb98d042e4a4c51a8d7d1c3ddc3b1ea091d0784"}, - {file = "jiter-0.6.1-cp311-none-win32.whl", hash = "sha256:7d72fc86474862c9c6d1f87b921b70c362f2b7e8b2e3c798bb7d58e419a6bc0f"}, - {file = "jiter-0.6.1-cp311-none-win_amd64.whl", hash = "sha256:3e36a320634f33a07794bb15b8da995dccb94f944d298c8cfe2bd99b1b8a574a"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1fad93654d5a7dcce0809aff66e883c98e2618b86656aeb2129db2cd6f26f867"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4e6e340e8cd92edab7f6a3a904dbbc8137e7f4b347c49a27da9814015cc0420c"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:691352e5653af84ed71763c3c427cff05e4d658c508172e01e9c956dfe004aba"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:defee3949313c1f5b55e18be45089970cdb936eb2a0063f5020c4185db1b63c9"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26d2bdd5da097e624081c6b5d416d3ee73e5b13f1703bcdadbb1881f0caa1933"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18aa9d1626b61c0734b973ed7088f8a3d690d0b7f5384a5270cd04f4d9f26c86"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3567c8228afa5ddcce950631c6b17397ed178003dc9ee7e567c4c4dcae9fa0"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5c0507131c922defe3f04c527d6838932fcdfd69facebafd7d3574fa3395314"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:540fcb224d7dc1bcf82f90f2ffb652df96f2851c031adca3c8741cb91877143b"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e7b75436d4fa2032b2530ad989e4cb0ca74c655975e3ff49f91a1a3d7f4e1df2"}, - {file = "jiter-0.6.1-cp312-none-win32.whl", hash = "sha256:883d2ced7c21bf06874fdeecab15014c1c6d82216765ca6deef08e335fa719e0"}, - {file = "jiter-0.6.1-cp312-none-win_amd64.whl", hash = "sha256:91e63273563401aadc6c52cca64a7921c50b29372441adc104127b910e98a5b6"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:852508a54fe3228432e56019da8b69208ea622a3069458252f725d634e955b31"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f491cc69ff44e5a1e8bc6bf2b94c1f98d179e1aaf4a554493c171a5b2316b701"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc56c8f0b2a28ad4d8047f3ae62d25d0e9ae01b99940ec0283263a04724de1f3"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51b58f7a0d9e084a43b28b23da2b09fc5e8df6aa2b6a27de43f991293cab85fd"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f79ce15099154c90ef900d69c6b4c686b64dfe23b0114e0971f2fecd306ec6c"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03a025b52009f47e53ea619175d17e4ded7c035c6fbd44935cb3ada11e1fd592"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74a8d93718137c021d9295248a87c2f9fdc0dcafead12d2930bc459ad40f885"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40b03b75f903975f68199fc4ec73d546150919cb7e534f3b51e727c4d6ccca5a"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:825651a3f04cf92a661d22cad61fc913400e33aa89b3e3ad9a6aa9dc8a1f5a71"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:928bf25eb69ddb292ab8177fe69d3fbf76c7feab5fce1c09265a7dccf25d3991"}, - {file = "jiter-0.6.1-cp313-none-win32.whl", hash = "sha256:352cd24121e80d3d053fab1cc9806258cad27c53cad99b7a3cac57cf934b12e4"}, - {file = "jiter-0.6.1-cp313-none-win_amd64.whl", hash = "sha256:be7503dd6f4bf02c2a9bacb5cc9335bc59132e7eee9d3e931b13d76fd80d7fda"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:31d8e00e1fb4c277df8ab6f31a671f509ebc791a80e5c61fdc6bc8696aaa297c"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77c296d65003cd7ee5d7b0965f6acbe6cffaf9d1fa420ea751f60ef24e85fed5"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeeb0c0325ef96c12a48ea7e23e2e86fe4838e6e0a995f464cf4c79fa791ceeb"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a31c6fcbe7d6c25d6f1cc6bb1cba576251d32795d09c09961174fe461a1fb5bd"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59e2b37f3b9401fc9e619f4d4badcab2e8643a721838bcf695c2318a0475ae42"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bae5ae4853cb9644144e9d0755854ce5108d470d31541d83f70ca7ecdc2d1637"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9df588e9c830b72d8db1dd7d0175af6706b0904f682ea9b1ca8b46028e54d6e9"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15f8395e835cf561c85c1adee72d899abf2733d9df72e9798e6d667c9b5c1f30"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a99d4e0b5fc3b05ea732d67eb2092fe894e95a90e6e413f2ea91387e228a307"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a311df1fa6be0ccd64c12abcd85458383d96e542531bafbfc0a16ff6feda588f"}, - {file = "jiter-0.6.1-cp38-none-win32.whl", hash = "sha256:81116a6c272a11347b199f0e16b6bd63f4c9d9b52bc108991397dd80d3c78aba"}, - {file = "jiter-0.6.1-cp38-none-win_amd64.whl", hash = "sha256:13f9084e3e871a7c0b6e710db54444088b1dd9fbefa54d449b630d5e73bb95d0"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f1c53615fcfec3b11527c08d19cff6bc870da567ce4e57676c059a3102d3a082"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f791b6a4da23238c17a81f44f5b55d08a420c5692c1fda84e301a4b036744eb1"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c97e90fec2da1d5f68ef121444c2c4fa72eabf3240829ad95cf6bbeca42a301"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbc1a66b4e41511209e97a2866898733c0110b7245791ac604117b7fb3fedb7"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e85f9e12cd8418ab10e1fcf0e335ae5bb3da26c4d13a0fd9e6a17a674783b6"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08be33db6dcc374c9cc19d3633af5e47961a7b10d4c61710bd39e48d52a35824"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:677be9550004f5e010d673d3b2a2b815a8ea07a71484a57d3f85dde7f14cf132"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8bd065be46c2eecc328e419d6557bbc37844c88bb07b7a8d2d6c91c7c4dedc9"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bd95375ce3609ec079a97c5d165afdd25693302c071ca60c7ae1cf826eb32022"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db459ed22d0208940d87f614e1f0ea5a946d29a3cfef71f7e1aab59b6c6b2afb"}, - {file = "jiter-0.6.1-cp39-none-win32.whl", hash = "sha256:d71c962f0971347bd552940ab96aa42ceefcd51b88c4ced8a27398182efa8d80"}, - {file = "jiter-0.6.1-cp39-none-win_amd64.whl", hash = "sha256:d465db62d2d10b489b7e7a33027c4ae3a64374425d757e963f86df5b5f2e7fc5"}, - {file = "jiter-0.6.1.tar.gz", hash = "sha256:e19cd21221fc139fb032e4112986656cb2739e9fe6d84c13956ab30ccc7d4449"}, + {file = "jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b"}, + {file = "jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49"}, + {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d"}, + {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff"}, + {file = "jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43"}, + {file = "jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105"}, + {file = "jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b"}, + {file = "jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc"}, + {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88"}, + {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6"}, + {file = "jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44"}, + {file = "jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855"}, + {file = "jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f"}, + {file = "jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d"}, + {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152"}, + {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29"}, + {file = "jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e"}, + {file = "jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c"}, + {file = "jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84"}, + {file = "jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1"}, + {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9"}, + {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05"}, + {file = "jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a"}, + {file = "jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865"}, + {file = "jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca"}, + {file = "jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0"}, + {file = "jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566"}, + {file = "jiter-0.8.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9e1fa156ee9454642adb7e7234a383884452532bc9d53d5af2d18d98ada1d79c"}, + {file = "jiter-0.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cf5dfa9956d96ff2efb0f8e9c7d055904012c952539a774305aaaf3abdf3d6c"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e52bf98c7e727dd44f7c4acb980cb988448faeafed8433c867888268899b298b"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a2ecaa3c23e7a7cf86d00eda3390c232f4d533cd9ddea4b04f5d0644faf642c5"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08d4c92bf480e19fc3f2717c9ce2aa31dceaa9163839a311424b6862252c943e"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99d9a1eded738299ba8e106c6779ce5c3893cffa0e32e4485d680588adae6db8"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20be8b7f606df096e08b0b1b4a3c6f0515e8dac296881fe7461dfa0fb5ec817"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d33f94615fcaf872f7fd8cd98ac3b429e435c77619777e8a449d9d27e01134d1"}, + {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:317b25e98a35ffec5c67efe56a4e9970852632c810d35b34ecdd70cc0e47b3b6"}, + {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc9043259ee430ecd71d178fccabd8c332a3bf1e81e50cae43cc2b28d19e4cb7"}, + {file = "jiter-0.8.2-cp38-cp38-win32.whl", hash = "sha256:fc5adda618205bd4678b146612ce44c3cbfdee9697951f2c0ffdef1f26d72b63"}, + {file = "jiter-0.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cd646c827b4f85ef4a78e4e58f4f5854fae0caf3db91b59f0d73731448a970c6"}, + {file = "jiter-0.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee"}, + {file = "jiter-0.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27"}, + {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841"}, + {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637"}, + {file = "jiter-0.8.2-cp39-cp39-win32.whl", hash = "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36"}, + {file = "jiter-0.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a"}, + {file = "jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d"}, ] [[package]] @@ -1807,7 +1881,7 @@ referencing = ">=0.31.0" [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" @@ -1900,44 +1974,34 @@ nearley = ["js2py"] regex = ["regex"] [[package]] -name = "llvmlite" -version = "0.43.0" -description = "lightweight wrapper around basic LLVM functionality" +name = "linkify-it-py" +version = "2.0.3" +description = "Links recognition library with FULL unicode support." optional = true -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "llvmlite-0.43.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a289af9a1687c6cf463478f0fa8e8aa3b6fb813317b0d70bf1ed0759eab6f761"}, - {file = "llvmlite-0.43.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d4fd101f571a31acb1559ae1af30f30b1dc4b3186669f92ad780e17c81e91bc"}, - {file = "llvmlite-0.43.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d434ec7e2ce3cc8f452d1cd9a28591745de022f931d67be688a737320dfcead"}, - {file = "llvmlite-0.43.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6912a87782acdff6eb8bf01675ed01d60ca1f2551f8176a300a886f09e836a6a"}, - {file = "llvmlite-0.43.0-cp310-cp310-win_amd64.whl", hash = "sha256:14f0e4bf2fd2d9a75a3534111e8ebeb08eda2f33e9bdd6dfa13282afacdde0ed"}, - {file = "llvmlite-0.43.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e8d0618cb9bfe40ac38a9633f2493d4d4e9fcc2f438d39a4e854f39cc0f5f98"}, - {file = "llvmlite-0.43.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0a9a1a39d4bf3517f2af9d23d479b4175ead205c592ceeb8b89af48a327ea57"}, - {file = "llvmlite-0.43.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1da416ab53e4f7f3bc8d4eeba36d801cc1894b9fbfbf2022b29b6bad34a7df2"}, - {file = "llvmlite-0.43.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977525a1e5f4059316b183fb4fd34fa858c9eade31f165427a3977c95e3ee749"}, - {file = "llvmlite-0.43.0-cp311-cp311-win_amd64.whl", hash = "sha256:d5bd550001d26450bd90777736c69d68c487d17bf371438f975229b2b8241a91"}, - {file = "llvmlite-0.43.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f99b600aa7f65235a5a05d0b9a9f31150c390f31261f2a0ba678e26823ec38f7"}, - {file = "llvmlite-0.43.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:35d80d61d0cda2d767f72de99450766250560399edc309da16937b93d3b676e7"}, - {file = "llvmlite-0.43.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eccce86bba940bae0d8d48ed925f21dbb813519169246e2ab292b5092aba121f"}, - {file = "llvmlite-0.43.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6509e1507ca0760787a199d19439cc887bfd82226f5af746d6977bd9f66844"}, - {file = "llvmlite-0.43.0-cp312-cp312-win_amd64.whl", hash = "sha256:7a2872ee80dcf6b5dbdc838763d26554c2a18aa833d31a2635bff16aafefb9c9"}, - {file = "llvmlite-0.43.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cd2a7376f7b3367019b664c21f0c61766219faa3b03731113ead75107f3b66c"}, - {file = "llvmlite-0.43.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18e9953c748b105668487b7c81a3e97b046d8abf95c4ddc0cd3c94f4e4651ae8"}, - {file = "llvmlite-0.43.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74937acd22dc11b33946b67dca7680e6d103d6e90eeaaaf932603bec6fe7b03a"}, - {file = "llvmlite-0.43.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9efc739cc6ed760f795806f67889923f7274276f0eb45092a1473e40d9b867"}, - {file = "llvmlite-0.43.0-cp39-cp39-win_amd64.whl", hash = "sha256:47e147cdda9037f94b399bf03bfd8a6b6b1f2f90be94a454e3386f006455a9b4"}, - {file = "llvmlite-0.43.0.tar.gz", hash = "sha256:ae2b5b5c3ef67354824fb75517c8db5fbe93bc02cd9671f3c62271626bc041d5"}, + {file = "linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048"}, + {file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"}, ] +[package.dependencies] +uc-micro-py = "*" + +[package.extras] +benchmark = ["pytest", "pytest-benchmark"] +dev = ["black", "flake8", "isort", "pre-commit", "pyproject-flake8"] +doc = ["myst-parser", "sphinx", "sphinx-book-theme"] +test = ["coverage", "pytest", "pytest-cov"] + [[package]] name = "lm-format-enforcer" -version = "0.10.6" +version = "0.10.9" description = "Enforce the output format (JSON Schema, Regex etc) of a language model" optional = true python-versions = "<4.0,>=3.8" files = [ - {file = "lm_format_enforcer-0.10.6-py3-none-any.whl", hash = "sha256:cad5a0cfbc9708332b57586a43d2945612fbcf40f9098f3ba95740d1a467a896"}, - {file = "lm_format_enforcer-0.10.6.tar.gz", hash = "sha256:ca2f061e9cf22fbe9f5ada2bc774c2bd369e8649b806fb5d9080eee37449f4a6"}, + {file = "lm_format_enforcer-0.10.9-py3-none-any.whl", hash = "sha256:6f3602d3470f54b3ba10d356ea34cc136afbd13394a360949dd8d943a2f2471e"}, + {file = "lm_format_enforcer-0.10.9.tar.gz", hash = "sha256:3e0bfeaf9fac9f69c8947da554db9a19a76d0be6e85075055f2c70d0aca420da"}, ] [package.dependencies] @@ -1946,6 +2010,32 @@ packaging = "*" pydantic = ">=1.10.8" pyyaml = "*" +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = true +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +linkify-it-py = {version = ">=1,<3", optional = true, markers = "extra == \"linkify\""} +mdit-py-plugins = {version = "*", optional = true, markers = "extra == \"plugins\""} +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "3.0.2" @@ -2016,6 +2106,100 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +description = "Collection of plugins for markdown-it-py" +optional = true +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = true +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "memray" +version = "1.15.0" +description = "A memory profiler for Python applications" +optional = true +python-versions = ">=3.7.0" +files = [ + {file = "memray-1.15.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:9b623c0c651d611dd068236566a8a202250e3d59307c3a3f241acc47835e73eb"}, + {file = "memray-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74765f92887b7eed152e3b9f14c147c43bf0247417b18c7ea0dec173cd01633c"}, + {file = "memray-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a5c6be5f9c2280b5ba077cbfec4706f209f9c0c2cd3a53d949ab9f4ee1f6a255"}, + {file = "memray-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:68bdad519b644539440914e1f6a04995631d0e31311ebe0977d949f2125bb579"}, + {file = "memray-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4964c6bd555a0f1755dfdb97a8d9864e646054594449c66757441f7d7682405"}, + {file = "memray-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:92212b85c7d843126e4d343c8ca024f4a57537017b9ac7611864963b322aafae"}, + {file = "memray-1.15.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:cb8997e113378b9ac8bbd9b17f4f867fc5c1eea1980d873be3ebe4c2f1176784"}, + {file = "memray-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ee45d919d81bfeb33677357dd5d248f3cad1d56be2ebd1853d4615a9f965b11"}, + {file = "memray-1.15.0-cp311-cp311-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a6b740aad69e7e5f82ffff53a8edef1313ff0b5e9b7253912da16e905dcb1dcb"}, + {file = "memray-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0045611f2da496e35d37a5ddfa2b6a74bbc82e47087924c07b3f520448297b26"}, + {file = "memray-1.15.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca5688e33a833de604d0e2de01b5bf11a4ac1d768998f8831a375a343dc7acaf"}, + {file = "memray-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbad938c3fdcebe0cf3c568fb8f8633ab37ab08ad4db167e0991e214d6f595b"}, + {file = "memray-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4eb50295bd87a091a85ec71f0ee612c5d709df490fea8a3adc4410f5da4f695"}, + {file = "memray-1.15.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:d13554a25129593872b5fbcd55ac34453239e51d9b6ace258329596ccce22bb3"}, + {file = "memray-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8cfe15962a9002ede8b1f8b4f045d95855100a8a60a9bf0d9f2b92950f914189"}, + {file = "memray-1.15.0-cp312-cp312-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e84b39adca05e720bdbf950cc92ef4bafefa2d6160111e5fc427cf59c6c16d1a"}, + {file = "memray-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7745d2c58dfc33ef77f8827053cb957131420051b67e2d5642b605d0e65a586"}, + {file = "memray-1.15.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:412225d85db0ec22142a82646d85ecc1e8680d33adbfd15789c7eaa356ad4107"}, + {file = "memray-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25ab7a7e32fedab46219121dfb6ec3e42c66984b217572fdd4cddc37359c521"}, + {file = "memray-1.15.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fb885f92833279d34addc607831352e91267b8e547ea861ad561a3dba64f6757"}, + {file = "memray-1.15.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:c1308e6a5fc5bc4e183bc0fdf5e241ddd9fb374338f32d77a4d5e74ccf611ef1"}, + {file = "memray-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0794227dfa4b86a56137211fd5b8ec131e0bc4a5dc41c2f5a318ca56a22c9331"}, + {file = "memray-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f184e82debd4f0c8ecf8e6034efddccdd9fac22909553a7f094eabf0902cd53f"}, + {file = "memray-1.15.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3493c5ac1ae1353fd0d24481bc9f30da8960ef703bf4af966cefff9dd1234d38"}, + {file = "memray-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:145a3062d8bf631aa8dc4b0928585e201282634afc369799dae1a0b9ece59fd4"}, + {file = "memray-1.15.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:59a4ade09cfe46e85cdb3a1976e9768e4674a6e448533c415dbe84e5a834f7c3"}, + {file = "memray-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bb9870f41fe0c4cd4612fded51174f5b837f3bc6364c57b4a60e65016ccc1f7a"}, + {file = "memray-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:26cb3cac3810bbe9e701d40463c185cf9e7faac3965a0e2b309df1a9fc18cd9a"}, + {file = "memray-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:317287025cabd541f9fdec615b3c7ff394798113feea0edb92d31bc9f06eafd0"}, + {file = "memray-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:850eba1e3063d97172b0990a14f61782682baeb48f6ae039c0bb86b2f4d19b75"}, + {file = "memray-1.15.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:aa5150e3b58ba6184fac2a97426ee66f996dffe0571bbf09bffe23836318772e"}, + {file = "memray-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:753632eed43161131bb632799dc53b7ccb7e6341b8ca8ef4ad68ff8da81e766a"}, + {file = "memray-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:727190a81516e1955932c307ac6a55a3aedb5799bc2edf6a8fbf49852e851f0c"}, + {file = "memray-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:413b145445110900a99fb78b1fb6932c2e3ffadd35df5b258f8ac0a25e0aaf90"}, + {file = "memray-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2518a298ffa6c5a2ddfa6a36d196aa4aef5bb33c5d95a26565aac6a7f5fcb0c0"}, + {file = "memray-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae46cb726c4c06121614995b877365680f196fa4549698aa5026c494a40e1a24"}, + {file = "memray-1.15.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:ce28c6a4d89349c43d76ad35ff1c21057230086cfcf18c6f4c2305df108bf0cd"}, + {file = "memray-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:671c2fd8c835caad80c2023baf6cdc4326c0f6dd4ae8bf1d7dbf6ad700c13625"}, + {file = "memray-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8404f3969e071e35364fd99d238da8ef245cf7ee2c790f3d46cd5b41cbac0541"}, + {file = "memray-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3e4c940deae29ea64d8dd4ffaee804f541a413c3c3c061a469837ed35d486b7"}, + {file = "memray-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36720d9ee97dee6cd51b230cbd2556cc3e0215c5a569b97c1faebc927ac3c505"}, + {file = "memray-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cba7727bfdee596f71323195af0262508ed0aec7ebbf67d98de0b959d9b8cf02"}, + {file = "memray-1.15.0.tar.gz", hash = "sha256:1beffa2bcba3dbe0f095d547927286eca46e272798b83026dd1b5db58e16ed56"}, +] + +[package.dependencies] +jinja2 = ">=2.9" +rich = ">=11.2.0" +textual = ">=0.41.0" + +[package.extras] +benchmark = ["asv"] +dev = ["Cython", "IPython", "asv", "black", "bump2version", "check-manifest", "flake8", "furo", "greenlet", "ipython", "isort", "mypy", "packaging", "pytest", "pytest-cov", "pytest-textual-snapshot", "setuptools", "sphinx", "sphinx-argparse", "textual (>=0.43,!=0.65.2,!=0.66)", "towncrier"] +docs = ["IPython", "bump2version", "furo", "sphinx", "sphinx-argparse", "towncrier"] +lint = ["black", "check-manifest", "flake8", "isort", "mypy"] +test = ["Cython", "greenlet", "ipython", "packaging", "pytest", "pytest-cov", "pytest-textual-snapshot", "setuptools", "textual (>=0.43,!=0.65.2,!=0.66)"] + [[package]] name = "mistral-common" version = "1.5.1" @@ -2060,13 +2244,13 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msal" -version = "1.31.0" +version = "1.31.1" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" files = [ - {file = "msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7"}, - {file = "msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b"}, + {file = "msal-1.31.1-py3-none-any.whl", hash = "sha256:29d9882de247e96db01386496d59f29035e5e841bcac892e6d7bf4390bf6bd17"}, + {file = "msal-1.31.1.tar.gz", hash = "sha256:11b5e6a3f802ffd3a72107203e20c4eac6ef53401961b880af2835b723d80578"}, ] [package.dependencies] @@ -2167,54 +2351,54 @@ files = [ [[package]] name = "msgspec" -version = "0.18.6" +version = "0.19.0" description = "A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "msgspec-0.18.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77f30b0234eceeff0f651119b9821ce80949b4d667ad38f3bfed0d0ebf9d6d8f"}, - {file = "msgspec-0.18.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a76b60e501b3932782a9da039bd1cd552b7d8dec54ce38332b87136c64852dd"}, - {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06acbd6edf175bee0e36295d6b0302c6de3aaf61246b46f9549ca0041a9d7177"}, - {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40a4df891676d9c28a67c2cc39947c33de516335680d1316a89e8f7218660410"}, - {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6896f4cd5b4b7d688018805520769a8446df911eb93b421c6c68155cdf9dd5a"}, - {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ac4dd63fd5309dd42a8c8c36c1563531069152be7819518be0a9d03be9788e4"}, - {file = "msgspec-0.18.6-cp310-cp310-win_amd64.whl", hash = "sha256:fda4c357145cf0b760000c4ad597e19b53adf01382b711f281720a10a0fe72b7"}, - {file = "msgspec-0.18.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e77e56ffe2701e83a96e35770c6adb655ffc074d530018d1b584a8e635b4f36f"}, - {file = "msgspec-0.18.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5351afb216b743df4b6b147691523697ff3a2fc5f3d54f771e91219f5c23aaa"}, - {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3232fabacef86fe8323cecbe99abbc5c02f7698e3f5f2e248e3480b66a3596b"}, - {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b524df6ea9998bbc99ea6ee4d0276a101bcc1aa8d14887bb823914d9f60d07"}, - {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f67c1d81272131895bb20d388dd8d341390acd0e192a55ab02d4d6468b434c"}, - {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0feb7a03d971c1c0353de1a8fe30bb6579c2dc5ccf29b5f7c7ab01172010492"}, - {file = "msgspec-0.18.6-cp311-cp311-win_amd64.whl", hash = "sha256:41cf758d3f40428c235c0f27bc6f322d43063bc32da7b9643e3f805c21ed57b4"}, - {file = "msgspec-0.18.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d86f5071fe33e19500920333c11e2267a31942d18fed4d9de5bc2fbab267d28c"}, - {file = "msgspec-0.18.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce13981bfa06f5eb126a3a5a38b1976bddb49a36e4f46d8e6edecf33ccf11df1"}, - {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97dec6932ad5e3ee1e3c14718638ba333befc45e0661caa57033cd4cc489466"}, - {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad237100393f637b297926cae1868b0d500f764ccd2f0623a380e2bcfb2809ca"}, - {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db1d8626748fa5d29bbd15da58b2d73af25b10aa98abf85aab8028119188ed57"}, - {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d70cb3d00d9f4de14d0b31d38dfe60c88ae16f3182988246a9861259c6722af6"}, - {file = "msgspec-0.18.6-cp312-cp312-win_amd64.whl", hash = "sha256:1003c20bfe9c6114cc16ea5db9c5466e49fae3d7f5e2e59cb70693190ad34da0"}, - {file = "msgspec-0.18.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7d9faed6dfff654a9ca7d9b0068456517f63dbc3aa704a527f493b9200b210a"}, - {file = "msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9da21f804c1a1471f26d32b5d9bc0480450ea77fbb8d9db431463ab64aaac2cf"}, - {file = "msgspec-0.18.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46eb2f6b22b0e61c137e65795b97dc515860bf6ec761d8fb65fdb62aa094ba61"}, - {file = "msgspec-0.18.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8355b55c80ac3e04885d72db515817d9fbb0def3bab936bba104e99ad22cf46"}, - {file = "msgspec-0.18.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9080eb12b8f59e177bd1eb5c21e24dd2ba2fa88a1dbc9a98e05ad7779b54c681"}, - {file = "msgspec-0.18.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cc001cf39becf8d2dcd3f413a4797c55009b3a3cdbf78a8bf5a7ca8fdb76032c"}, - {file = "msgspec-0.18.6-cp38-cp38-win_amd64.whl", hash = "sha256:fac5834e14ac4da1fca373753e0c4ec9c8069d1fe5f534fa5208453b6065d5be"}, - {file = "msgspec-0.18.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:974d3520fcc6b824a6dedbdf2b411df31a73e6e7414301abac62e6b8d03791b4"}, - {file = "msgspec-0.18.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd62e5818731a66aaa8e9b0a1e5543dc979a46278da01e85c3c9a1a4f047ef7e"}, - {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7481355a1adcf1f08dedd9311193c674ffb8bf7b79314b4314752b89a2cf7f1c"}, - {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aa85198f8f154cf35d6f979998f6dadd3dc46a8a8c714632f53f5d65b315c07"}, - {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e24539b25c85c8f0597274f11061c102ad6b0c56af053373ba4629772b407be"}, - {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c61ee4d3be03ea9cd089f7c8e36158786cd06e51fbb62529276452bbf2d52ece"}, - {file = "msgspec-0.18.6-cp39-cp39-win_amd64.whl", hash = "sha256:b5c390b0b0b7da879520d4ae26044d74aeee5144f83087eb7842ba59c02bc090"}, - {file = "msgspec-0.18.6.tar.gz", hash = "sha256:a59fc3b4fcdb972d09138cb516dbde600c99d07c38fd9372a6ef500d2d031b4e"}, + {file = "msgspec-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d8dd848ee7ca7c8153462557655570156c2be94e79acec3561cf379581343259"}, + {file = "msgspec-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0553bbc77662e5708fe66aa75e7bd3e4b0f209709c48b299afd791d711a93c36"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe2c4bf29bf4e89790b3117470dea2c20b59932772483082c468b990d45fb947"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e87ecfa9795ee5214861eab8326b0e75475c2e68a384002aa135ea2a27d909"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3c4ec642689da44618f68c90855a10edbc6ac3ff7c1d94395446c65a776e712a"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2719647625320b60e2d8af06b35f5b12d4f4d281db30a15a1df22adb2295f633"}, + {file = "msgspec-0.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:695b832d0091edd86eeb535cd39e45f3919f48d997685f7ac31acb15e0a2ed90"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa77046904db764b0462036bc63ef71f02b75b8f72e9c9dd4c447d6da1ed8f8e"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:047cfa8675eb3bad68722cfe95c60e7afabf84d1bd8938979dd2b92e9e4a9551"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78f46ff39a427e10b4a61614a2777ad69559cc8d603a7c05681f5a595ea98f7"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c7adf191e4bd3be0e9231c3b6dc20cf1199ada2af523885efc2ed218eafd011"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f04cad4385e20be7c7176bb8ae3dca54a08e9756cfc97bcdb4f18560c3042063"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45c8fb410670b3b7eb884d44a75589377c341ec1392b778311acdbfa55187716"}, + {file = "msgspec-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:70eaef4934b87193a27d802534dc466778ad8d536e296ae2f9334e182ac27b6c"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537"}, + {file = "msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327"}, + {file = "msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15c1e86fff77184c20a2932cd9742bf33fe23125fa3fcf332df9ad2f7d483044"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b5541b2b3294e5ffabe31a09d604e23a88533ace36ac288fa32a420aa38d229"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f5c043ace7962ef188746e83b99faaa9e3e699ab857ca3f367b309c8e2c6b12"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca06aa08e39bf57e39a258e1996474f84d0dd8130d486c00bec26d797b8c5446"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e695dad6897896e9384cf5e2687d9ae9feaef50e802f93602d35458e20d1fb19"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3be5c02e1fee57b54130316a08fe40cca53af92999a302a6054cd451700ea7db"}, + {file = "msgspec-0.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:0684573a821be3c749912acf5848cce78af4298345cb2d7a8b8948a0a5a27cfe"}, + {file = "msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e"}, ] [package.extras] -dev = ["attrs", "coverage", "furo", "gcovr", "ipython", "msgpack", "mypy", "pre-commit", "pyright", "pytest", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "tomli", "tomli-w"] +dev = ["attrs", "coverage", "eval-type-backport", "furo", "ipython", "msgpack", "mypy", "pre-commit", "pyright", "pytest", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "tomli", "tomli_w"] doc = ["furo", "ipython", "sphinx", "sphinx-copybutton", "sphinx-design"] -test = ["attrs", "msgpack", "mypy", "pyright", "pytest", "pyyaml", "tomli", "tomli-w"] -toml = ["tomli", "tomli-w"] +test = ["attrs", "eval-type-backport", "msgpack", "pytest", "pyyaml", "tomli", "tomli_w"] +toml = ["tomli", "tomli_w"] yaml = ["pyyaml"] [[package]] @@ -2321,34 +2505,6 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} -[[package]] -name = "multiprocess" -version = "0.70.15" -description = "better multiprocessing and multithreading in Python" -optional = true -python-versions = ">=3.7" -files = [ - {file = "multiprocess-0.70.15-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aa36c7ed16f508091438687fe9baa393a7a8e206731d321e443745e743a0d4e5"}, - {file = "multiprocess-0.70.15-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:20e024018c46d0d1602024c613007ac948f9754659e3853b0aa705e83f6931d8"}, - {file = "multiprocess-0.70.15-pp37-pypy37_pp73-manylinux_2_24_i686.whl", hash = "sha256:e576062981c91f0fe8a463c3d52506e598dfc51320a8dd8d78b987dfca91c5db"}, - {file = "multiprocess-0.70.15-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e73f497e6696a0f5433ada2b3d599ae733b87a6e8b008e387c62ac9127add177"}, - {file = "multiprocess-0.70.15-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:73db2e7b32dcc7f9b0f075c2ffa45c90b6729d3f1805f27e88534c8d321a1be5"}, - {file = "multiprocess-0.70.15-pp38-pypy38_pp73-manylinux_2_24_i686.whl", hash = "sha256:4271647bd8a49c28ecd6eb56a7fdbd3c212c45529ad5303b40b3c65fc6928e5f"}, - {file = "multiprocess-0.70.15-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:cf981fb998d6ec3208cb14f0cf2e9e80216e834f5d51fd09ebc937c32b960902"}, - {file = "multiprocess-0.70.15-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:18f9f2c7063346d1617bd1684fdcae8d33380ae96b99427260f562e1a1228b67"}, - {file = "multiprocess-0.70.15-pp39-pypy39_pp73-manylinux_2_24_i686.whl", hash = "sha256:0eac53214d664c49a34695e5824872db4006b1a465edd7459a251809c3773370"}, - {file = "multiprocess-0.70.15-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1a51dd34096db47fb21fa2b839e615b051d51b97af9a67afbcdaa67186b44883"}, - {file = "multiprocess-0.70.15-py310-none-any.whl", hash = "sha256:7dd58e33235e83cf09d625e55cffd7b0f0eede7ee9223cdd666a87624f60c21a"}, - {file = "multiprocess-0.70.15-py311-none-any.whl", hash = "sha256:134f89053d82c9ed3b73edd3a2531eb791e602d4f4156fc92a79259590bd9670"}, - {file = "multiprocess-0.70.15-py37-none-any.whl", hash = "sha256:f7d4a1629bccb433114c3b4885f69eccc200994323c80f6feee73b0edc9199c5"}, - {file = "multiprocess-0.70.15-py38-none-any.whl", hash = "sha256:bee9afba476c91f9ebee7beeee0601face9eff67d822e893f9a893725fbd6316"}, - {file = "multiprocess-0.70.15-py39-none-any.whl", hash = "sha256:3e0953f5d52b4c76f1c973eaf8214554d146f2be5decb48e928e55c7a2d19338"}, - {file = "multiprocess-0.70.15.tar.gz", hash = "sha256:f20eed3036c0ef477b07a4177cf7c1ba520d9a2677870a4f47fe026f0cd6787e"}, -] - -[package.dependencies] -dill = ">=0.3.7" - [[package]] name = "mypy" version = "0.991" @@ -2439,40 +2595,6 @@ doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9. extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] -[[package]] -name = "numba" -version = "0.60.0" -description = "compiling Python code using LLVM" -optional = true -python-versions = ">=3.9" -files = [ - {file = "numba-0.60.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d761de835cd38fb400d2c26bb103a2726f548dc30368853121d66201672e651"}, - {file = "numba-0.60.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:159e618ef213fba758837f9837fb402bbe65326e60ba0633dbe6c7f274d42c1b"}, - {file = "numba-0.60.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1527dc578b95c7c4ff248792ec33d097ba6bef9eda466c948b68dfc995c25781"}, - {file = "numba-0.60.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe0b28abb8d70f8160798f4de9d486143200f34458d34c4a214114e445d7124e"}, - {file = "numba-0.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:19407ced081d7e2e4b8d8c36aa57b7452e0283871c296e12d798852bc7d7f198"}, - {file = "numba-0.60.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a17b70fc9e380ee29c42717e8cc0bfaa5556c416d94f9aa96ba13acb41bdece8"}, - {file = "numba-0.60.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fb02b344a2a80efa6f677aa5c40cd5dd452e1b35f8d1c2af0dfd9ada9978e4b"}, - {file = "numba-0.60.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f4fde652ea604ea3c86508a3fb31556a6157b2c76c8b51b1d45eb40c8598703"}, - {file = "numba-0.60.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4142d7ac0210cc86432b818338a2bc368dc773a2f5cf1e32ff7c5b378bd63ee8"}, - {file = "numba-0.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:cac02c041e9b5bc8cf8f2034ff6f0dbafccd1ae9590dc146b3a02a45e53af4e2"}, - {file = "numba-0.60.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7da4098db31182fc5ffe4bc42c6f24cd7d1cb8a14b59fd755bfee32e34b8404"}, - {file = "numba-0.60.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38d6ea4c1f56417076ecf8fc327c831ae793282e0ff51080c5094cb726507b1c"}, - {file = "numba-0.60.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:62908d29fb6a3229c242e981ca27e32a6e606cc253fc9e8faeb0e48760de241e"}, - {file = "numba-0.60.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ebaa91538e996f708f1ab30ef4d3ddc344b64b5227b67a57aa74f401bb68b9d"}, - {file = "numba-0.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:f75262e8fe7fa96db1dca93d53a194a38c46da28b112b8a4aca168f0df860347"}, - {file = "numba-0.60.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:01ef4cd7d83abe087d644eaa3d95831b777aa21d441a23703d649e06b8e06b74"}, - {file = "numba-0.60.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:819a3dfd4630d95fd574036f99e47212a1af41cbcb019bf8afac63ff56834449"}, - {file = "numba-0.60.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b983bd6ad82fe868493012487f34eae8bf7dd94654951404114f23c3466d34b"}, - {file = "numba-0.60.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c151748cd269ddeab66334bd754817ffc0cabd9433acb0f551697e5151917d25"}, - {file = "numba-0.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:3031547a015710140e8c87226b4cfe927cac199835e5bf7d4fe5cb64e814e3ab"}, - {file = "numba-0.60.0.tar.gz", hash = "sha256:5df6158e5584eece5fc83294b949fd30b9f1125df7708862205217e068aabf16"}, -] - -[package.dependencies] -llvmlite = "==0.43.*" -numpy = ">=1.22,<2.1" - [[package]] name = "numpy" version = "1.26.4" @@ -2520,46 +2642,50 @@ files = [ [[package]] name = "nvidia-cublas-cu12" -version = "12.1.3.1" +version = "12.4.5.8" description = "CUBLAS native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, - {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, ] [[package]] name = "nvidia-cuda-cupti-cu12" -version = "12.1.105" +version = "12.4.127" description = "CUDA profiling tools runtime libs." optional = false python-versions = ">=3" files = [ - {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, - {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, ] [[package]] name = "nvidia-cuda-nvrtc-cu12" -version = "12.1.105" +version = "12.4.127" description = "NVRTC native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, - {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, ] [[package]] name = "nvidia-cuda-runtime-cu12" -version = "12.1.105" +version = "12.4.127" description = "CUDA Runtime native Libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, - {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, ] [[package]] @@ -2578,35 +2704,41 @@ nvidia-cublas-cu12 = "*" [[package]] name = "nvidia-cufft-cu12" -version = "11.0.2.54" +version = "11.2.1.3" description = "CUFFT native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, - {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-win_amd64.whl", hash = "sha256:d802f4954291101186078ccbe22fc285a902136f974d369540fd4a5333d1440b"}, ] +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-curand-cu12" -version = "10.3.2.106" +version = "10.3.5.147" description = "CURAND native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, - {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, ] [[package]] name = "nvidia-cusolver-cu12" -version = "11.4.5.107" +version = "11.6.1.9" description = "CUDA solver native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, - {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-win_amd64.whl", hash = "sha256:e77314c9d7b694fcebc84f58989f3aa4fb4cb442f12ca1a9bde50f5e8f6d1b9c"}, ] [package.dependencies] @@ -2616,13 +2748,14 @@ nvidia-nvjitlink-cu12 = "*" [[package]] name = "nvidia-cusparse-cu12" -version = "12.1.0.106" +version = "12.3.1.170" description = "CUSPARSE native runtime libraries" optional = false python-versions = ">=3" files = [ - {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, - {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-win_amd64.whl", hash = "sha256:9bc90fb087bc7b4c15641521f31c0371e9a612fc2ba12c338d3ae032e6b6797f"}, ] [package.dependencies] @@ -2641,13 +2774,12 @@ files = [ [[package]] name = "nvidia-nccl-cu12" -version = "2.20.5" +version = "2.21.5" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = false python-versions = ">=3" files = [ - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01"}, - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56"}, + {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, ] [[package]] @@ -2664,13 +2796,14 @@ files = [ [[package]] name = "nvidia-nvtx-cu12" -version = "12.1.105" +version = "12.4.127" description = "NVIDIA Tools Extension" optional = false python-versions = ">=3" files = [ - {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, - {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, ] [[package]] @@ -2691,13 +2824,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "1.52.2" +version = "1.59.5" description = "The official Python library for the openai API" optional = true -python-versions = ">=3.7.1" +python-versions = ">=3.8" files = [ - {file = "openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc"}, - {file = "openai-1.52.2.tar.gz", hash = "sha256:87b7d0f69d85f5641678d414b7ee3082363647a5c66a462ed7f3ccb59582da0d"}, + {file = "openai-1.59.5-py3-none-any.whl", hash = "sha256:e646b44856b0dda9345d3c43639e056334d792d1690e99690313c0ef7ca4d8cc"}, + {file = "openai-1.59.5.tar.gz", hash = "sha256:9886e77c02dad9dc6a7b67a11ab372a56842a9b5d376aa476672175ab10e83a0"}, ] [package.dependencies] @@ -2712,6 +2845,34 @@ typing-extensions = ">=4.11,<5" [package.extras] datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] +realtime = ["websockets (>=13,<15)"] + +[[package]] +name = "opencensus" +version = "0.11.4" +description = "A stats collection and distributed tracing framework" +optional = true +python-versions = "*" +files = [ + {file = "opencensus-0.11.4-py2.py3-none-any.whl", hash = "sha256:a18487ce68bc19900336e0ff4655c5a116daf10c1b3685ece8d971bddad6a864"}, + {file = "opencensus-0.11.4.tar.gz", hash = "sha256:cbef87d8b8773064ab60e5c2a1ced58bbaa38a6d052c41aec224958ce544eff2"}, +] + +[package.dependencies] +google-api-core = {version = ">=1.0.0,<3.0.0", markers = "python_version >= \"3.6\""} +opencensus-context = ">=0.1.3" +six = ">=1.16,<2.0" + +[[package]] +name = "opencensus-context" +version = "0.1.3" +description = "OpenCensus Runtime Context" +optional = true +python-versions = "*" +files = [ + {file = "opencensus-context-0.1.3.tar.gz", hash = "sha256:a03108c3c10d8c80bb5ddf5c8a1f033161fa61972a9917f9b9b3a18517f0088c"}, + {file = "opencensus_context-0.1.3-py2.py3-none-any.whl", hash = "sha256:073bb0590007af276853009fac7e4bab1d523c3f03baf4cb4511ca38967c6039"}, +] [[package]] name = "opencv-python-headless" @@ -2741,114 +2902,178 @@ numpy = [ [[package]] name = "orjson" -version = "3.10.10" +version = "3.10.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b788a579b113acf1c57e0a68e558be71d5d09aa67f62ca1f68e01117e550a998"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:804b18e2b88022c8905bb79bd2cbe59c0cd014b9328f43da8d3b28441995cda4"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9972572a1d042ec9ee421b6da69f7cc823da5962237563fa548ab17f152f0b9b"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc6993ab1c2ae7dd0711161e303f1db69062955ac2668181bfdf2dd410e65258"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d78e4cacced5781b01d9bc0f0cd8b70b906a0e109825cb41c1b03f9c41e4ce86"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6eb2598df518281ba0cbc30d24c5b06124ccf7e19169e883c14e0831217a0bc"}, - {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23776265c5215ec532de6238a52707048401a568f0fa0d938008e92a147fe2c7"}, - {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cc2a654c08755cef90b468ff17c102e2def0edd62898b2486767204a7f5cc9c"}, - {file = "orjson-3.10.10-cp310-none-win32.whl", hash = "sha256:081b3fc6a86d72efeb67c13d0ea7c030017bd95f9868b1e329a376edc456153b"}, - {file = "orjson-3.10.10-cp310-none-win_amd64.whl", hash = "sha256:ff38c5fb749347768a603be1fb8a31856458af839f31f064c5aa74aca5be9efe"}, - {file = "orjson-3.10.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:879e99486c0fbb256266c7c6a67ff84f46035e4f8749ac6317cc83dacd7f993a"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019481fa9ea5ff13b5d5d95e6fd5ab25ded0810c80b150c2c7b1cc8660b662a7"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0dd57eff09894938b4c86d4b871a479260f9e156fa7f12f8cad4b39ea8028bb5"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbde6d70cd95ab4d11ea8ac5e738e30764e510fc54d777336eec09bb93b8576c"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2625cb37b8fb42e2147404e5ff7ef08712099197a9cd38895006d7053e69d6"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbf3c20c6a7db69df58672a0d5815647ecf78c8e62a4d9bd284e8621c1fe5ccb"}, - {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:75c38f5647e02d423807d252ce4528bf6a95bd776af999cb1fb48867ed01d1f6"}, - {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23458d31fa50ec18e0ec4b0b4343730928296b11111df5f547c75913714116b2"}, - {file = "orjson-3.10.10-cp311-none-win32.whl", hash = "sha256:2787cd9dedc591c989f3facd7e3e86508eafdc9536a26ec277699c0aa63c685b"}, - {file = "orjson-3.10.10-cp311-none-win_amd64.whl", hash = "sha256:6514449d2c202a75183f807bc755167713297c69f1db57a89a1ef4a0170ee269"}, - {file = "orjson-3.10.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8564f48f3620861f5ef1e080ce7cd122ee89d7d6dacf25fcae675ff63b4d6e05"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bf161a32b479034098c5b81f2608f09167ad2fa1c06abd4e527ea6bf4837a9"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b65c93617bcafa7f04b74ae8bc2cc214bd5cb45168a953256ff83015c6747d"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8e28406f97fc2ea0c6150f4c1b6e8261453318930b334abc419214c82314f85"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4d0d9fe174cc7a5bdce2e6c378bcdb4c49b2bf522a8f996aa586020e1b96cee"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3be81c42f1242cbed03cbb3973501fcaa2675a0af638f8be494eaf37143d999"}, - {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65f9886d3bae65be026219c0a5f32dbbe91a9e6272f56d092ab22561ad0ea33b"}, - {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b"}, - {file = "orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f"}, - {file = "orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f"}, - {file = "orjson-3.10.10-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44bffae68c291f94ff5a9b4149fe9d1bdd4cd0ff0fb575bcea8351d48db629a1"}, - {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e27b4c6437315df3024f0835887127dac2a0a3ff643500ec27088d2588fa5ae1"}, - {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca84df16d6b49325a4084fd8b2fe2229cb415e15c46c529f868c3387bb1339d"}, - {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c14ce70e8f39bd71f9f80423801b5d10bf93d1dceffdecd04df0f64d2c69bc01"}, - {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:24ac62336da9bda1bd93c0491eff0613003b48d3cb5d01470842e7b52a40d5b4"}, - {file = "orjson-3.10.10-cp313-none-win32.whl", hash = "sha256:eb0a42831372ec2b05acc9ee45af77bcaccbd91257345f93780a8e654efc75db"}, - {file = "orjson-3.10.10-cp313-none-win_amd64.whl", hash = "sha256:f0c4f37f8bf3f1075c6cc8dd8a9f843689a4b618628f8812d0a71e6968b95ffd"}, - {file = "orjson-3.10.10-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:829700cc18503efc0cf502d630f612884258020d98a317679cd2054af0259568"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0ceb5e0e8c4f010ac787d29ae6299846935044686509e2f0f06ed441c1ca949"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c25908eb86968613216f3db4d3003f1c45d78eb9046b71056ca327ff92bdbd4"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:218cb0bc03340144b6328a9ff78f0932e642199ac184dd74b01ad691f42f93ff"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2277ec2cea3775640dc81ab5195bb5b2ada2fe0ea6eee4677474edc75ea6785"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:848ea3b55ab5ccc9d7bbd420d69432628b691fba3ca8ae3148c35156cbd282aa"}, - {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e3e67b537ac0c835b25b5f7d40d83816abd2d3f4c0b0866ee981a045287a54f3"}, - {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7948cfb909353fce2135dcdbe4521a5e7e1159484e0bb024c1722f272488f2b8"}, - {file = "orjson-3.10.10-cp38-none-win32.whl", hash = "sha256:78bee66a988f1a333dc0b6257503d63553b1957889c17b2c4ed72385cd1b96ae"}, - {file = "orjson-3.10.10-cp38-none-win_amd64.whl", hash = "sha256:f1d647ca8d62afeb774340a343c7fc023efacfd3a39f70c798991063f0c681dd"}, - {file = "orjson-3.10.10-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5a059afddbaa6dd733b5a2d76a90dbc8af790b993b1b5cb97a1176ca713b5df8"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f9b5c59f7e2a1a410f971c5ebc68f1995822837cd10905ee255f96074537ee6"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5ef198bafdef4aa9d49a4165ba53ffdc0a9e1c7b6f76178572ab33118afea25"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf29ce0bb5d3320824ec3d1508652421000ba466abd63bdd52c64bcce9eb1fa"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dddd5516bcc93e723d029c1633ae79c4417477b4f57dad9bfeeb6bc0315e654a"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12f2003695b10817f0fa8b8fca982ed7f5761dcb0d93cff4f2f9f6709903fd7"}, - {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:672f9874a8a8fb9bb1b771331d31ba27f57702c8106cdbadad8bda5d10bc1019"}, - {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dcbb0ca5fafb2b378b2c74419480ab2486326974826bbf6588f4dc62137570a"}, - {file = "orjson-3.10.10-cp39-none-win32.whl", hash = "sha256:d9bbd3a4b92256875cb058c3381b782649b9a3c68a4aa9a2fff020c2f9cfc1be"}, - {file = "orjson-3.10.10-cp39-none-win_amd64.whl", hash = "sha256:766f21487a53aee8524b97ca9582d5c6541b03ab6210fbaf10142ae2f3ced2aa"}, - {file = "orjson-3.10.10.tar.gz", hash = "sha256:37949383c4df7b4337ce82ee35b6d7471e55195efa7dcb45ab8226ceadb0fe3b"}, + {file = "orjson-3.10.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:849ea7845a55f09965826e816cdc7689d6cf74fe9223d79d758c714af955bcb6"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5947b139dfa33f72eecc63f17e45230a97e741942955a6c9e650069305eb73d"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cde6d76910d3179dae70f164466692f4ea36da124d6fb1a61399ca589e81d69a"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6dfbaeb7afa77ca608a50e2770a0461177b63a99520d4928e27591b142c74b1"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa45e489ef80f28ff0e5ba0a72812b8cfc7c1ef8b46a694723807d1b07c89ebb"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f5007abfdbb1d866e2aa8990bd1c465f0f6da71d19e695fc278282be12cffa5"}, + {file = "orjson-3.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1b49e2af011c84c3f2d541bb5cd1e3c7c2df672223e7e3ea608f09cf295e5f8a"}, + {file = "orjson-3.10.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:164ac155109226b3a2606ee6dda899ccfbe6e7e18b5bdc3fbc00f79cc074157d"}, + {file = "orjson-3.10.14-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6b1225024cf0ef5d15934b5ffe9baf860fe8bc68a796513f5ea4f5056de30bca"}, + {file = "orjson-3.10.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d6546e8073dc382e60fcae4a001a5a1bc46da5eab4a4878acc2d12072d6166d5"}, + {file = "orjson-3.10.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9f1d2942605c894162252d6259b0121bf1cb493071a1ea8cb35d79cb3e6ac5bc"}, + {file = "orjson-3.10.14-cp310-cp310-win32.whl", hash = "sha256:397083806abd51cf2b3bbbf6c347575374d160331a2d33c5823e22249ad3118b"}, + {file = "orjson-3.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:fa18f949d3183a8d468367056be989666ac2bef3a72eece0bade9cdb733b3c28"}, + {file = "orjson-3.10.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f506fd666dd1ecd15a832bebc66c4df45c1902fd47526292836c339f7ba665a9"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efe5fd254cfb0eeee13b8ef7ecb20f5d5a56ddda8a587f3852ab2cedfefdb5f6"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ddc8c866d7467f5ee2991397d2ea94bcf60d0048bdd8ca555740b56f9042725"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af8e42ae4363773658b8d578d56dedffb4f05ceeb4d1d4dd3fb504950b45526"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84dd83110503bc10e94322bf3ffab8bc49150176b49b4984dc1cce4c0a993bf9"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f5bfc0399cd4811bf10ec7a759c7ab0cd18080956af8ee138097d5b5296a95"}, + {file = "orjson-3.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868943660fb2a1e6b6b965b74430c16a79320b665b28dd4511d15ad5038d37d5"}, + {file = "orjson-3.10.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:33449c67195969b1a677533dee9d76e006001213a24501333624623e13c7cc8e"}, + {file = "orjson-3.10.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4c9f60f9fb0b5be66e416dcd8c9d94c3eabff3801d875bdb1f8ffc12cf86905"}, + {file = "orjson-3.10.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0de4d6315cfdbd9ec803b945c23b3a68207fd47cbe43626036d97e8e9561a436"}, + {file = "orjson-3.10.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83adda3db595cb1a7e2237029b3249c85afbe5c747d26b41b802e7482cb3933e"}, + {file = "orjson-3.10.14-cp311-cp311-win32.whl", hash = "sha256:998019ef74a4997a9d741b1473533cdb8faa31373afc9849b35129b4b8ec048d"}, + {file = "orjson-3.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:9d034abdd36f0f0f2240f91492684e5043d46f290525d1117712d5b8137784eb"}, + {file = "orjson-3.10.14-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2ad4b7e367efba6dc3f119c9a0fcd41908b7ec0399a696f3cdea7ec477441b09"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f496286fc85e93ce0f71cc84fc1c42de2decf1bf494094e188e27a53694777a7"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c7f189bbfcded40e41a6969c1068ba305850ba016665be71a217918931416fbf"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cc8204f0b75606869c707da331058ddf085de29558b516fc43c73ee5ee2aadb"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deaa2899dff7f03ab667e2ec25842d233e2a6a9e333efa484dfe666403f3501c"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1c3ea52642c9714dc6e56de8a451a066f6d2707d273e07fe8a9cc1ba073813d"}, + {file = "orjson-3.10.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d3f9ed72e7458ded9a1fb1b4d4ed4c4fdbaf82030ce3f9274b4dc1bff7ace2b"}, + {file = "orjson-3.10.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:07520685d408a2aba514c17ccc16199ff2934f9f9e28501e676c557f454a37fe"}, + {file = "orjson-3.10.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:76344269b550ea01488d19a2a369ab572c1ac4449a72e9f6ac0d70eb1cbfb953"}, + {file = "orjson-3.10.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e2979d0f2959990620f7e62da6cd954e4620ee815539bc57a8ae46e2dacf90e3"}, + {file = "orjson-3.10.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03f61ca3674555adcb1aa717b9fc87ae936aa7a63f6aba90a474a88701278780"}, + {file = "orjson-3.10.14-cp312-cp312-win32.whl", hash = "sha256:d5075c54edf1d6ad81d4c6523ce54a748ba1208b542e54b97d8a882ecd810fd1"}, + {file = "orjson-3.10.14-cp312-cp312-win_amd64.whl", hash = "sha256:175cafd322e458603e8ce73510a068d16b6e6f389c13f69bf16de0e843d7d406"}, + {file = "orjson-3.10.14-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:0905ca08a10f7e0e0c97d11359609300eb1437490a7f32bbaa349de757e2e0c7"}, + {file = "orjson-3.10.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92d13292249f9f2a3e418cbc307a9fbbef043c65f4bd8ba1eb620bc2aaba3d15"}, + {file = "orjson-3.10.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90937664e776ad316d64251e2fa2ad69265e4443067668e4727074fe39676414"}, + {file = "orjson-3.10.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9ed3d26c4cb4f6babaf791aa46a029265850e80ec2a566581f5c2ee1a14df4f1"}, + {file = "orjson-3.10.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:56ee546c2bbe9599aba78169f99d1dc33301853e897dbaf642d654248280dc6e"}, + {file = "orjson-3.10.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:901e826cb2f1bdc1fcef3ef59adf0c451e8f7c0b5deb26c1a933fb66fb505eae"}, + {file = "orjson-3.10.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:26336c0d4b2d44636e1e1e6ed1002f03c6aae4a8a9329561c8883f135e9ff010"}, + {file = "orjson-3.10.14-cp313-cp313-win32.whl", hash = "sha256:e2bc525e335a8545c4e48f84dd0328bc46158c9aaeb8a1c2276546e94540ea3d"}, + {file = "orjson-3.10.14-cp313-cp313-win_amd64.whl", hash = "sha256:eca04dfd792cedad53dc9a917da1a522486255360cb4e77619343a20d9f35364"}, + {file = "orjson-3.10.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9a0fba3b8a587a54c18585f077dcab6dd251c170d85cfa4d063d5746cd595a0f"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:175abf3d20e737fec47261d278f95031736a49d7832a09ab684026528c4d96db"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29ca1a93e035d570e8b791b6c0feddd403c6a5388bfe870bf2aa6bba1b9d9b8e"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f77202c80e8ab5a1d1e9faf642343bee5aaf332061e1ada4e9147dbd9eb00c46"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e2ec73b7099b6a29b40a62e08a23b936423bd35529f8f55c42e27acccde7954"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2d1679df9f9cd9504f8dff24555c1eaabba8aad7f5914f28dab99e3c2552c9d"}, + {file = "orjson-3.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691ab9a13834310a263664313e4f747ceb93662d14a8bdf20eb97d27ed488f16"}, + {file = "orjson-3.10.14-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b11ed82054fce82fb74cea33247d825d05ad6a4015ecfc02af5fbce442fbf361"}, + {file = "orjson-3.10.14-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:e70a1d62b8288677d48f3bea66c21586a5f999c64ecd3878edb7393e8d1b548d"}, + {file = "orjson-3.10.14-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:16642f10c1ca5611251bd835de9914a4b03095e28a34c8ba6a5500b5074338bd"}, + {file = "orjson-3.10.14-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3871bad546aa66c155e3f36f99c459780c2a392d502a64e23fb96d9abf338511"}, + {file = "orjson-3.10.14-cp38-cp38-win32.whl", hash = "sha256:0293a88815e9bb5c90af4045f81ed364d982f955d12052d989d844d6c4e50945"}, + {file = "orjson-3.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:6169d3868b190d6b21adc8e61f64e3db30f50559dfbdef34a1cd6c738d409dfc"}, + {file = "orjson-3.10.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:06d4ec218b1ec1467d8d64da4e123b4794c781b536203c309ca0f52819a16c03"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962c2ec0dcaf22b76dee9831fdf0c4a33d4bf9a257a2bc5d4adc00d5c8ad9034"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:21d3be4132f71ef1360385770474f29ea1538a242eef72ac4934fe142800e37f"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28ed60597c149a9e3f5ad6dd9cebaee6fb2f0e3f2d159a4a2b9b862d4748860"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e947f70167fe18469f2023644e91ab3d24f9aed69a5e1c78e2c81b9cea553fb"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64410696c97a35af2432dea7bdc4ce32416458159430ef1b4beb79fd30093ad6"}, + {file = "orjson-3.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8050a5d81c022561ee29cd2739de5b4445f3c72f39423fde80a63299c1892c52"}, + {file = "orjson-3.10.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b49a28e30d3eca86db3fe6f9b7f4152fcacbb4a467953cd1b42b94b479b77956"}, + {file = "orjson-3.10.14-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ca041ad20291a65d853a9523744eebc3f5a4b2f7634e99f8fe88320695ddf766"}, + {file = "orjson-3.10.14-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d313a2998b74bb26e9e371851a173a9b9474764916f1fc7971095699b3c6e964"}, + {file = "orjson-3.10.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7796692136a67b3e301ef9052bde6fe8e7bd5200da766811a3a608ffa62aaff0"}, + {file = "orjson-3.10.14-cp39-cp39-win32.whl", hash = "sha256:eee4bc767f348fba485ed9dc576ca58b0a9eac237f0e160f7a59bce628ed06b3"}, + {file = "orjson-3.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:96a1c0ee30fb113b3ae3c748fd75ca74a157ff4c58476c47db4d61518962a011"}, + {file = "orjson-3.10.14.tar.gz", hash = "sha256:cf31f6f071a6b8e7aa1ead1fa27b935b48d00fbfa6a28ce856cfff2d5dd68eed"}, ] [[package]] name = "outlines" -version = "0.0.46" +version = "0.1.11" description = "Probabilistic Generative Model Programming" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "outlines-0.0.46-py3-none-any.whl", hash = "sha256:fea7b2ccd2dd82ddf11849a55ef14c4d7b72f12136a67d1b105b81639c8ca2b0"}, - {file = "outlines-0.0.46.tar.gz", hash = "sha256:cd272418a268e0a25b7189180dfdcf9fe1b99f50ac1dfb9ffd83c896c5b3fa3c"}, + {file = "outlines-0.1.11-py3-none-any.whl", hash = "sha256:f5a5f2242ed9802d3aab7a92789bf4008d734c576be9258cc0a297f690124727"}, + {file = "outlines-0.1.11.tar.gz", hash = "sha256:0997bd9da1cc050e430bd08995dc7d4bd855918bafa4531e49d3f37110a23aba"}, ] [package.dependencies] +airportsdata = "*" cloudpickle = "*" -datasets = "*" diskcache = "*" interegular = "*" jinja2 = "*" jsonschema = "*" lark = "*" -nest-asyncio = "*" -numba = "*" -numpy = "<2.0.0" -pyairports = "*" +nest_asyncio = "*" +numpy = "*" +outlines_core = "0.1.26" pycountry = "*" pydantic = ">=2.0" referencing = "*" requests = "*" +torch = "*" tqdm = "*" -typing-extensions = "*" +typing_extensions = "*" [package.extras] +exllamav2 = ["exllamav2"] +llamacpp = ["datasets", "llama-cpp-python", "numpy (<2)", "transformers"] +mlxlm = ["datasets", "mlx-lm"] +openai = ["openai"] serve = ["fastapi", "pydantic (>=2.0)", "uvicorn", "vllm (>=0.3.0)"] -test = ["accelerate", "beartype (<0.16.0)", "coverage[toml] (>=5.1)", "diff-cover", "huggingface-hub", "llama-cpp-python", "mlx-lm", "openai (>=1.0.0)", "pre-commit", "pytest", "pytest-benchmark", "pytest-cov", "pytest-mock", "responses", "torch", "transformers", "vllm"] +test = ["accelerate", "beartype (<0.16.0)", "coverage[toml] (>=5.1)", "datasets", "diff-cover", "exllamav2", "huggingface_hub", "jax", "llama-cpp-python", "mlx-lm (>=0.19.2)", "openai (>=1.0.0)", "pillow", "pre-commit", "pytest", "pytest-benchmark", "pytest-cov", "pytest-mock", "responses", "transformers", "vllm"] +transformers = ["accelerate", "datasets", "numpy (<2)", "transformers"] +vllm = ["numpy (<2)", "transformers", "vllm"] + +[[package]] +name = "outlines-core" +version = "0.1.26" +description = "Structured Text Generation in Rust" +optional = true +python-versions = ">=3.8" +files = [ + {file = "outlines_core-0.1.26-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6a962a7452e7ac170fa04d405342cadae2d28fafa5b1830cef7aa610257ed32f"}, + {file = "outlines_core-0.1.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15a3684fa29564da2db03934cf0097bef3e871f70d3af0ef2b52fdb886da2e09"}, + {file = "outlines_core-0.1.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64e01c0cfa9ba371634d7c3f6ea1862397cef98e4509fe98e3f57faa721a72d6"}, + {file = "outlines_core-0.1.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3c4196148e47f455f1ace78e329d5b97e531cbc406456d681592952adae7e17"}, + {file = "outlines_core-0.1.26-cp310-cp310-win32.whl", hash = "sha256:f38d290a7f6e5e12cbfcaee03269dfc0dbda49b360024b4279d1aba251fdc346"}, + {file = "outlines_core-0.1.26-cp310-cp310-win_amd64.whl", hash = "sha256:11ff56af56cb54c563b7f25d86cd9ee77f3fed825f1d4dccd9449bb1e4e89538"}, + {file = "outlines_core-0.1.26-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b6787b07b7c673fc3087d2b537719ecac8e03b10a47d032dd1926985c32885b0"}, + {file = "outlines_core-0.1.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e0ea28a76da31d25b6f53242bf13e1b59a0241badf82353c88f55e1cf81b128"}, + {file = "outlines_core-0.1.26-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8932044a3d9329be53a226118850638f85b4d7842f9b863d0a123f23de220cd"}, + {file = "outlines_core-0.1.26-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84b7cd2fb6268bf990dd3d479ffb4fa0bace6f571cb85b15b6cdb44b84f5b69"}, + {file = "outlines_core-0.1.26-cp311-cp311-win32.whl", hash = "sha256:f19765c151abfc970996368080aeea6d2a19e927817fe4e2af6726e639be3de4"}, + {file = "outlines_core-0.1.26-cp311-cp311-win_amd64.whl", hash = "sha256:3f59aeccea21ed6ff3cf52102fd163f26d279821c20e5127ddd18d4ea4d0c8d2"}, + {file = "outlines_core-0.1.26-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f54633bca50055d42ea4d94ae06dcbe52d3d76a9b621b75723b1177d0d952953"}, + {file = "outlines_core-0.1.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9525321b48700dcaaabf60bcdc951e45f9357ba3fb3e1bfc81b662d7d4170e7c"}, + {file = "outlines_core-0.1.26-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00f409f72c11f6ffadb57066950dd384d5388015028c1a1a615c9a64988dae3e"}, + {file = "outlines_core-0.1.26-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e86a1bb46adc5cbf6dfd7a7fe4105e0e2a4c6e041732a053126b41c521a1f223"}, + {file = "outlines_core-0.1.26-cp312-cp312-win32.whl", hash = "sha256:19f462f6b00935708677ad27cb4df55e0e17f6ffe713ab750f5f2683b090f95d"}, + {file = "outlines_core-0.1.26-cp312-cp312-win_amd64.whl", hash = "sha256:9b36bff12779e58883747116893a17b3551bbd10865878b951b03a44d112229a"}, + {file = "outlines_core-0.1.26-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7b7849cf40028319ebb9d8ba0fe4c590ef5888eebe524a81b3af30aaa06ea21c"}, + {file = "outlines_core-0.1.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2f8641aab4a6bd84516907492ce82099503129da01b3c29c1dc9ad50320bae77"}, + {file = "outlines_core-0.1.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bba56604efdbc5932c7a8a88c2b8b0d0c740ab883b0012fb5464a9736796802b"}, + {file = "outlines_core-0.1.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cc8c87d89bd267356f8149c9066cbb98970425ec162997fbf195c3f1feb7009"}, + {file = "outlines_core-0.1.26-cp39-cp39-win32.whl", hash = "sha256:9d792a43ed9d8a4e1b38f4d83fe99db442d57aad4404c2edf98b710892eda47e"}, + {file = "outlines_core-0.1.26-cp39-cp39-win_amd64.whl", hash = "sha256:ad8564ecd7b64bcb840596c5049ff1c1a96346de494302ffcc0f2b188c15675e"}, + {file = "outlines_core-0.1.26.tar.gz", hash = "sha256:481c4301341e77cc8f1832d616784adb4d461b4fec65878e7c0d2cba7163a189"}, +] + +[package.dependencies] +interegular = "*" +jsonschema = "*" + +[package.extras] +test = ["accelerate", "asv", "beartype (<0.16.0)", "coverage[toml] (>=5.1)", "datasets", "diff-cover", "huggingface_hub", "numpy", "pillow", "pre-commit", "psutil", "pydantic", "pytest", "pytest-benchmark", "pytest-cov", "pytest-mock", "scipy", "setuptools-rust", "torch", "transformers"] [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -2939,13 +3164,13 @@ xml = ["lxml (>=4.9.2)"] [[package]] name = "partial-json-parser" -version = "0.2.1.1.post4" +version = "0.2.1.1.post5" description = "Parse partial JSON generated by LLM" optional = true python-versions = ">=3.6" files = [ - {file = "partial_json_parser-0.2.1.1.post4-py3-none-any.whl", hash = "sha256:960144ff29ab9358b69c17dca6e867687438f0dd206ea113677040f14f9ccedd"}, - {file = "partial_json_parser-0.2.1.1.post4.tar.gz", hash = "sha256:a38f11ceb89a86fbfbd0acad4170d417dcb317621c6ec9ab5f2b6652f3f460bf"}, + {file = "partial_json_parser-0.2.1.1.post5-py3-none-any.whl", hash = "sha256:627715aaa3cb3fb60a65b0d62223243acaa6c70846520a90326fef3a2f0b61ca"}, + {file = "partial_json_parser-0.2.1.1.post5.tar.gz", hash = "sha256:992710ac67e90b367921d52727698928040f7713ba7ecb33b96371ea7aec82ca"}, ] [package.extras] @@ -3140,109 +3365,93 @@ starlette = ">=0.30.0,<1.0.0" [[package]] name = "propcache" -version = "0.2.0" +version = "0.2.1" description = "Accelerated property cache" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, - {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, - {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, - {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, - {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, - {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, - {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, - {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, - {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, - {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, - {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, - {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, - {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, - {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, - {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, ] [[package]] @@ -3322,70 +3531,22 @@ files = [ ] [[package]] -name = "pyairports" -version = "2.1.1" -description = "Airport and other locations database" +name = "py-spy" +version = "0.4.0" +description = "Sampling profiler for Python programs" optional = true python-versions = "*" files = [ - {file = "pyairports-2.1.1-py3-none-any.whl", hash = "sha256:3dfa0cc3e47696692ade92feccdc6b046968f2a75f5e30f65735d6db7251cb26"}, - {file = "pyairports-2.1.1.tar.gz", hash = "sha256:3d60a727fce4da81b9c6393ea8ae0b33d67b37ece344dffc863f749e3ad62bcd"}, -] - -[[package]] -name = "pyarrow" -version = "18.0.0" -description = "Python library for Apache Arrow" -optional = true -python-versions = ">=3.9" -files = [ - {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2333f93260674e185cfbf208d2da3007132572e56871f451ba1a556b45dae6e2"}, - {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4c381857754da44326f3a49b8b199f7f87a51c2faacd5114352fc78de30d3aba"}, - {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:603cd8ad4976568954598ef0a6d4ed3dfb78aff3d57fa8d6271f470f0ce7d34f"}, - {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58a62549a3e0bc9e03df32f350e10e1efb94ec6cf63e3920c3385b26663948ce"}, - {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bc97316840a349485fbb137eb8d0f4d7057e1b2c1272b1a20eebbbe1848f5122"}, - {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:2e549a748fa8b8715e734919923f69318c953e077e9c02140ada13e59d043310"}, - {file = "pyarrow-18.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:606e9a3dcb0f52307c5040698ea962685fb1c852d72379ee9412be7de9c5f9e2"}, - {file = "pyarrow-18.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d5795e37c0a33baa618c5e054cd61f586cf76850a251e2b21355e4085def6280"}, - {file = "pyarrow-18.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:5f0510608ccd6e7f02ca8596962afb8c6cc84c453e7be0da4d85f5f4f7b0328a"}, - {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616ea2826c03c16e87f517c46296621a7c51e30400f6d0a61be645f203aa2b93"}, - {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1824f5b029ddd289919f354bc285992cb4e32da518758c136271cf66046ef22"}, - {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6dd1b52d0d58dd8f685ced9971eb49f697d753aa7912f0a8f50833c7a7426319"}, - {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:320ae9bd45ad7ecc12ec858b3e8e462578de060832b98fc4d671dee9f10d9954"}, - {file = "pyarrow-18.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:2c992716cffb1088414f2b478f7af0175fd0a76fea80841b1706baa8fb0ebaad"}, - {file = "pyarrow-18.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:e7ab04f272f98ebffd2a0661e4e126036f6936391ba2889ed2d44c5006237802"}, - {file = "pyarrow-18.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:03f40b65a43be159d2f97fd64dc998f769d0995a50c00f07aab58b0b3da87e1f"}, - {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be08af84808dff63a76860847c48ec0416928a7b3a17c2f49a072cac7c45efbd"}, - {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70c1965cde991b711a98448ccda3486f2a336457cf4ec4dca257a926e149c9"}, - {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:00178509f379415a3fcf855af020e3340254f990a8534294ec3cf674d6e255fd"}, - {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a71ab0589a63a3e987beb2bc172e05f000a5c5be2636b4b263c44034e215b5d7"}, - {file = "pyarrow-18.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe92efcdbfa0bcf2fa602e466d7f2905500f33f09eb90bf0bcf2e6ca41b574c8"}, - {file = "pyarrow-18.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:907ee0aa8ca576f5e0cdc20b5aeb2ad4d3953a3b4769fc4b499e00ef0266f02f"}, - {file = "pyarrow-18.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:66dcc216ebae2eb4c37b223feaf82f15b69d502821dde2da138ec5a3716e7463"}, - {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc1daf7c425f58527900876354390ee41b0ae962a73ad0959b9d829def583bb1"}, - {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:871b292d4b696b09120ed5bde894f79ee2a5f109cb84470546471df264cae136"}, - {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:082ba62bdcb939824ba1ce10b8acef5ab621da1f4c4805e07bfd153617ac19d4"}, - {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:2c664ab88b9766413197733c1720d3dcd4190e8fa3bbdc3710384630a0a7207b"}, - {file = "pyarrow-18.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc892be34dbd058e8d189b47db1e33a227d965ea8805a235c8a7286f7fd17d3a"}, - {file = "pyarrow-18.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:28f9c39a56d2c78bf6b87dcc699d520ab850919d4a8c7418cd20eda49874a2ea"}, - {file = "pyarrow-18.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:f1a198a50c409ab2d009fbf20956ace84567d67f2c5701511d4dd561fae6f32e"}, - {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5bd7fd32e3ace012d43925ea4fc8bd1b02cc6cc1e9813b518302950e89b5a22"}, - {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336addb8b6f5208be1b2398442c703a710b6b937b1a046065ee4db65e782ff5a"}, - {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:45476490dd4adec5472c92b4d253e245258745d0ccaabe706f8d03288ed60a79"}, - {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420"}, - {file = "pyarrow-18.0.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:eb7e3abcda7e1e6b83c2dc2909c8d045881017270a119cc6ee7fdcfe71d02df8"}, - {file = "pyarrow-18.0.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:09f30690b99ce34e0da64d20dab372ee54431745e4efb78ac938234a282d15f9"}, - {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5ca5d707e158540312e09fd907f9f49bacbe779ab5236d9699ced14d2293b8"}, - {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6331f280c6e4521c69b201a42dd978f60f7e129511a55da9e0bfe426b4ebb8d"}, - {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3ac24b2be732e78a5a3ac0b3aa870d73766dd00beba6e015ea2ea7394f8b4e55"}, - {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b30a927c6dff89ee702686596f27c25160dd6c99be5bcc1513a763ae5b1bfc03"}, - {file = "pyarrow-18.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:8f40ec677e942374e3d7f2fad6a67a4c2811a8b975e8703c6fd26d3b168a90e2"}, - {file = "pyarrow-18.0.0.tar.gz", hash = "sha256:a6aa027b1a9d2970cf328ccd6dbe4a996bc13c39fd427f502782f5bdb9ca20f5"}, + {file = "py_spy-0.4.0-py2.py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f2cf3f7130e7d780471faa5957441d3b4e0ec39a79b2c00f4c33d494f7728428"}, + {file = "py_spy-0.4.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:47cdda4c34d9b6cb01f3aaeceb2e88faf57da880207fe72ff6ff97e9bb6cc8a9"}, + {file = "py_spy-0.4.0-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eee3d0bde85ca5cf4f01f012d461180ca76c24835a96f7b5c4ded64eb6a008ab"}, + {file = "py_spy-0.4.0-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5f06ffce4c9c98b7fc9f5e67e5e7db591173f1351837633f3f23d9378b1d18a"}, + {file = "py_spy-0.4.0-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87573e64dbfdfc89ba2e0f5e2f525aa84e0299c7eb6454b47ea335fde583a7a0"}, + {file = "py_spy-0.4.0-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8bf2f3702cef367a489faa45177b41a6c31b2a3e5bd78c978d44e29340152f5a"}, + {file = "py_spy-0.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:77d8f637ade38367d944874776f45b703b7ac5938b1f7be8891f3a5876ddbb96"}, + {file = "py_spy-0.4.0.tar.gz", hash = "sha256:806602ce7972782cc9c1e383f339bfc27bfb822d42485e6a3e0530ae5040e1f0"}, ] -[package.extras] -test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] - [[package]] name = "pyasn1" version = "0.6.1" @@ -3411,6 +3572,20 @@ files = [ [package.dependencies] pyasn1 = ">=0.4.6,<0.7.0" +[[package]] +name = "pybind11" +version = "2.13.6" +description = "Seamless operability between C++11 and Python" +optional = true +python-versions = ">=3.7" +files = [ + {file = "pybind11-2.13.6-py3-none-any.whl", hash = "sha256:237c41e29157b962835d356b370ededd57594a26d5894a795960f0047cb5caf5"}, + {file = "pybind11-2.13.6.tar.gz", hash = "sha256:ba6af10348c12b24e92fa086b39cfba0eff619b61ac77c406167d813b096d39a"}, +] + +[package.extras] +global = ["pybind11-global (==2.13.6)"] + [[package]] name = "pycountry" version = "24.6.1" @@ -3435,19 +3610,19 @@ files = [ [[package]] name = "pydantic" -version = "2.9.2" +version = "2.10.4" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, + {file = "pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d"}, + {file = "pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.4" -typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -3455,114 +3630,139 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.4" +version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, - {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, - {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, - {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, - {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, - {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, - {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, - {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, - {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, - {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, - {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, - {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, - {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, - {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pygments" +version = "2.19.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = true +python-versions = ">=3.8" +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pyjwt" -version = "2.9.0" +version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, - {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, ] [package.dependencies] @@ -3901,60 +4101,74 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "ray" -version = "2.38.0" +version = "2.40.0" description = "Ray provides a simple, universal API for building distributed applications." optional = true python-versions = ">=3.9" files = [ - {file = "ray-2.38.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:fe01fce188ddea96ca5c7dfa4a783d2e5d80662318a640fae58d89e6eaf2cd7f"}, - {file = "ray-2.38.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fa0833cc54ca0c48aebc98b813fa1e990a20c8ee1da857073e11eb72696d316"}, - {file = "ray-2.38.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3cdd71617f935a0d741864e94061093d14fad659e67271c9a779108878294ac3"}, - {file = "ray-2.38.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:3a7d6f7159bce4117bfe8f9c3d0b65ff27257fe2dd8d737dad0f3869666440da"}, - {file = "ray-2.38.0-cp310-cp310-win_amd64.whl", hash = "sha256:b56c78ebdd7535ab6e8566e66c1f1c65a694432875dd683b1310e3d7b9af79f3"}, - {file = "ray-2.38.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:cce1a39fa91fe08b15d2d62d084052968a155c8528415f248346567aa589580c"}, - {file = "ray-2.38.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:454f576b3dbef2231693e3081ba5bf093add610c72ebf3c17788943f6653fe68"}, - {file = "ray-2.38.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:282a326d2848d411c3ce305e57e2de8357e24cb9becbec7e507e8800572c487e"}, - {file = "ray-2.38.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:ece802cf3a1c102b53f63b8bc90d947971c4b387deaf233c224ed8ef34a1f3cb"}, - {file = "ray-2.38.0-cp311-cp311-win_amd64.whl", hash = "sha256:64f7cd908177dd50089469cf331afbeb22e61e26d0a4be210ad20dccddbf6efb"}, - {file = "ray-2.38.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:10174ac63406b95a0a795a89396aeb8966286f15558087127719b13c367b40e3"}, - {file = "ray-2.38.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ea4148e929c17543378ba8909398fc81ce09d8e2257fc21afa62fc88ba4babc2"}, - {file = "ray-2.38.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:d4efaf1cfc727d60d78cc7112ff8eaa67634a5327e2a84f8dcaab5d167fe7fec"}, - {file = "ray-2.38.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:07507d2f9961e8d5390c0eb606df249216ef5afb1ff8185581f3e92041d66293"}, - {file = "ray-2.38.0-cp312-cp312-win_amd64.whl", hash = "sha256:6fdef893cbe617ac9d079e65702e9f1b3f455835f05b6f8b46467cf2184a52dc"}, - {file = "ray-2.38.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:0910eb721943f9825d10ae16d9cd3c7de70f4dde985207e18fddf59c0126770f"}, - {file = "ray-2.38.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d0bd0d7a116ab79864ca8bf3222758ad85cc9f9421a51136ca33429e8e87ed9"}, - {file = "ray-2.38.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:cdfd910da985bc3c985945b7bbbef5f891473eddd06af9208b8af0d020e3a9a7"}, - {file = "ray-2.38.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e18ac9e23da17393b4447ef2924e11ef95bb8a5d5b561ca8c74c05f2a594a6fe"}, - {file = "ray-2.38.0-cp39-cp39-win_amd64.whl", hash = "sha256:1f0d014f215b25f92041d4a2acfbc4e44abb2a92f43971228f493ba7874ede00"}, + {file = "ray-2.40.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:064af8bc52cc988c82470b8e76e5df417737fa7c1d87f597a892c69eb4ec3caa"}, + {file = "ray-2.40.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:45beb4019cd20b6cb10572d8012c771bccd623f544a669da6797ccf993c4bb33"}, + {file = "ray-2.40.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:6cede5fbf7de4fae22cebe2c6977aaf3c85fde6f7de2aa10c46992cf24ea8bda"}, + {file = "ray-2.40.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:f6eab11dc8490f88e78e06aa645905b259cde1fa03b15e8426155c4782ba0bbe"}, + {file = "ray-2.40.0-cp310-cp310-win_amd64.whl", hash = "sha256:f83cda1ecceb7abe021cd377f0c503596f26d2d66cdff13c1089a06c8b780c23"}, + {file = "ray-2.40.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:dac89bb2cb889c19549a4ac0383492e7550f3e63b78b629a3118e8b91e4e82f3"}, + {file = "ray-2.40.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e4efdf8aebff6e71391c2d5dd66bb45835f2d6d629ac03a3e21e2d4283e2311"}, + {file = "ray-2.40.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:c776f131e5d0a169a98ab8021c5796f52bf48fcfc6c44ffbd2a9d090fe10748a"}, + {file = "ray-2.40.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:71711cbf2c156213fd49b0f9cc93180a7ba424110070a34bdea3dc09527f31df"}, + {file = "ray-2.40.0-cp311-cp311-win_amd64.whl", hash = "sha256:532321132618983366e39aeb4cc7867cf7241b0b1e49ee44b01d2aee9923e422"}, + {file = "ray-2.40.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:6992922fe91a90b5cc97d9f05ca51b64d72cd644db7ad55caa936be9a6098cce"}, + {file = "ray-2.40.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:28329e7a7471610a475d3bb09a4c1b31abcf3596cee25c4254f8d01ad161ba84"}, + {file = "ray-2.40.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:8ea05221fa48e32c652c29498d320e90134b3a012421006af98965097dd1cc3b"}, + {file = "ray-2.40.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:674755814f5692306c554cadbc24015af823dc0516e34bdef24ccac9d7a656e3"}, + {file = "ray-2.40.0-cp312-cp312-win_amd64.whl", hash = "sha256:bbc01d773cbc43e3efa462ec28ee4c0cacc50f098078332fb45b1ab38eaf9b5d"}, + {file = "ray-2.40.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:27292bf8921dd69757e7581644afcd3ccae13d6f10f3841f5523ae82b6612f4b"}, + {file = "ray-2.40.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b74ca43d0c4ccdcaefbf1e7d26aabb1c0d20f825688a9fd7134ba918bda8442"}, + {file = "ray-2.40.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5eb7a203f58defedff0dc53f78a4e1431d040b2b8458548704979c0113f3b892"}, + {file = "ray-2.40.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:a36a20a3b936b36d14fab031222f92e3c5e731d7db6bb183ca4fba6d0ce3f52a"}, + {file = "ray-2.40.0-cp39-cp39-win_amd64.whl", hash = "sha256:fbe9cd3e076dea676afd57caf19b2897a67ecdf14a542c03864800966cf2aec9"}, ] [package.dependencies] +aiohttp = {version = ">=3.7", optional = true, markers = "extra == \"default\""} +aiohttp-cors = {version = "*", optional = true, markers = "extra == \"default\""} aiosignal = "*" click = ">=7.0" +colorful = {version = "*", optional = true, markers = "extra == \"default\""} filelock = "*" frozenlist = "*" +grpcio = [ + {version = ">=1.42.0", optional = true, markers = "python_version >= \"3.10\" and extra == \"default\""}, + {version = ">=1.32.0", optional = true, markers = "python_version < \"3.10\" and extra == \"default\""}, +] jsonschema = "*" +memray = {version = "*", optional = true, markers = "sys_platform != \"win32\" and extra == \"default\""} msgpack = ">=1.0.0,<2.0.0" +opencensus = {version = "*", optional = true, markers = "extra == \"default\""} packaging = "*" +prometheus-client = {version = ">=0.7.1", optional = true, markers = "extra == \"default\""} protobuf = ">=3.15.3,<3.19.5 || >3.19.5" +py-spy = {version = ">=0.2.0", optional = true, markers = "extra == \"default\""} +pydantic = {version = "<2.0.dev0 || >=2.5.dev0,<3", optional = true, markers = "extra == \"default\""} pyyaml = "*" requests = "*" +smart-open = {version = "*", optional = true, markers = "extra == \"default\""} +virtualenv = {version = ">=20.0.24,<20.21.1 || >20.21.1", optional = true, markers = "extra == \"default\""} [package.extras] adag = ["cupy-cuda12x"] -air = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "fastapi", "fsspec", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "memray", "numpy (>=1.20)", "opencensus", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyarrow (>=6.0.1)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "requests", "smart-open", "starlette", "tensorboardX (>=1.9)", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] -all = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "cupy-cuda12x", "dm-tree", "fastapi", "fsspec", "grpcio (!=1.56.0)", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "gymnasium (==0.28.1)", "lz4", "memray", "numpy (>=1.20)", "opencensus", "opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyOpenSSL", "pyarrow (>=6.0.1)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "pyyaml", "requests", "rich", "scikit-image", "scipy", "smart-open", "starlette", "tensorboardX (>=1.9)", "typer", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] -all-cpp = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "cupy-cuda12x", "dm-tree", "fastapi", "fsspec", "grpcio (!=1.56.0)", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "gymnasium (==0.28.1)", "lz4", "memray", "numpy (>=1.20)", "opencensus", "opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyOpenSSL", "pyarrow (>=6.0.1)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "pyyaml", "ray-cpp (==2.38.0)", "requests", "rich", "scikit-image", "scipy", "smart-open", "starlette", "tensorboardX (>=1.9)", "typer", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] +air = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "fastapi", "fsspec", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "memray", "numpy (>=1.20)", "opencensus", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyarrow (<18)", "pyarrow (>=9.0.0)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "requests", "smart-open", "starlette", "tensorboardX (>=1.9)", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] +all = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "cupy-cuda12x", "dm-tree", "fastapi", "fsspec", "grpcio (!=1.56.0)", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "gymnasium (==1.0.0)", "lz4", "memray", "numpy (>=1.20)", "opencensus", "opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyOpenSSL", "pyarrow (<18)", "pyarrow (>=9.0.0)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "pyyaml", "requests", "rich", "scikit-image", "scipy", "smart-open", "starlette", "tensorboardX (>=1.9)", "typer", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] +all-cpp = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "cupy-cuda12x", "dm-tree", "fastapi", "fsspec", "grpcio (!=1.56.0)", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "gymnasium (==1.0.0)", "lz4", "memray", "numpy (>=1.20)", "opencensus", "opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk", "pandas", "pandas (>=1.3)", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyOpenSSL", "pyarrow (<18)", "pyarrow (>=9.0.0)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "pyyaml", "ray-cpp (==2.40.0)", "requests", "rich", "scikit-image", "scipy", "smart-open", "starlette", "tensorboardX (>=1.9)", "typer", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] client = ["grpcio (!=1.56.0)"] -cpp = ["ray-cpp (==2.38.0)"] -data = ["fsspec", "numpy (>=1.20)", "pandas (>=1.3)", "pyarrow (>=6.0.1)"] +cpp = ["ray-cpp (==2.40.0)"] +data = ["fsspec", "numpy (>=1.20)", "pandas (>=1.3)", "pyarrow (<18)", "pyarrow (>=9.0.0)"] default = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "memray", "opencensus", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "requests", "smart-open", "virtualenv (>=20.0.24,!=20.21.1)"] observability = ["opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk"] -rllib = ["dm-tree", "fsspec", "gymnasium (==0.28.1)", "lz4", "pandas", "pyarrow (>=6.0.1)", "pyyaml", "requests", "rich", "scikit-image", "scipy", "tensorboardX (>=1.9)", "typer"] +rllib = ["dm-tree", "fsspec", "gymnasium (==1.0.0)", "lz4", "pandas", "pyarrow (<18)", "pyarrow (>=9.0.0)", "pyyaml", "requests", "rich", "scikit-image", "scipy", "tensorboardX (>=1.9)", "typer"] serve = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "fastapi", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "memray", "opencensus", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "requests", "smart-open", "starlette", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] serve-grpc = ["aiohttp (>=3.7)", "aiohttp-cors", "colorful", "fastapi", "grpcio (>=1.32.0)", "grpcio (>=1.42.0)", "memray", "opencensus", "prometheus-client (>=0.7.1)", "py-spy (>=0.2.0)", "pyOpenSSL", "pydantic (<2.0.dev0 || >=2.5.dev0,<3)", "requests", "smart-open", "starlette", "uvicorn[standard]", "virtualenv (>=20.0.24,!=20.21.1)", "watchfiles"] -train = ["fsspec", "pandas", "pyarrow (>=6.0.1)", "requests", "tensorboardX (>=1.9)"] -tune = ["fsspec", "pandas", "pyarrow (>=6.0.1)", "requests", "tensorboardX (>=1.9)"] +train = ["fsspec", "pandas", "pyarrow (<18)", "pyarrow (>=9.0.0)", "requests", "tensorboardX (>=1.9)"] +tune = ["fsspec", "pandas", "pyarrow (<18)", "pyarrow (>=9.0.0)", "requests", "tensorboardX (>=1.9)"] [[package]] name = "referencing" @@ -3973,105 +4187,105 @@ rpds-py = ">=0.7.0" [[package]] name = "regex" -version = "2024.9.11" +version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, - {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, - {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, - {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, - {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, - {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, - {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, - {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, - {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, - {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, - {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, - {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, - {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, - {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, ] [[package]] @@ -4113,116 +4327,135 @@ requests = ">=2.0.0" [package.extras] rsa = ["oauthlib[signedtoken] (>=3.0.0)"] +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = true +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rpds-py" -version = "0.20.0" +version = "0.22.3" description = "Python bindings to Rust's persistent data structures (rpds)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, - {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, - {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, - {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, - {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, - {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, - {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, - {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, - {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, - {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, - {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, - {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, - {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, - {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, - {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, + {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, + {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, + {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, + {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, + {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, + {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, + {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, + {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, + {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, + {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, + {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, ] [[package]] @@ -4241,13 +4474,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "s3transfer" -version = "0.10.3" +version = "0.10.4" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d"}, - {file = "s3transfer-0.10.3.tar.gz", hash = "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c"}, + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, ] [package.dependencies] @@ -4258,121 +4491,26 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "safetensors" -version = "0.4.5" +version = "0.5.2" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "safetensors-0.4.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a63eaccd22243c67e4f2b1c3e258b257effc4acd78f3b9d397edc8cf8f1298a7"}, - {file = "safetensors-0.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:23fc9b4ec7b602915cbb4ec1a7c1ad96d2743c322f20ab709e2c35d1b66dad27"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6885016f34bef80ea1085b7e99b3c1f92cb1be78a49839203060f67b40aee761"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:133620f443450429322f238fda74d512c4008621227fccf2f8cf4a76206fea7c"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fb3e0609ec12d2a77e882f07cced530b8262027f64b75d399f1504ffec0ba56"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0f1dd769f064adc33831f5e97ad07babbd728427f98e3e1db6902e369122737"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6d156bdb26732feada84f9388a9f135528c1ef5b05fae153da365ad4319c4c5"}, - {file = "safetensors-0.4.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e347d77e2c77eb7624400ccd09bed69d35c0332f417ce8c048d404a096c593b"}, - {file = "safetensors-0.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9f556eea3aec1d3d955403159fe2123ddd68e880f83954ee9b4a3f2e15e716b6"}, - {file = "safetensors-0.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9483f42be3b6bc8ff77dd67302de8ae411c4db39f7224dec66b0eb95822e4163"}, - {file = "safetensors-0.4.5-cp310-none-win32.whl", hash = "sha256:7389129c03fadd1ccc37fd1ebbc773f2b031483b04700923c3511d2a939252cc"}, - {file = "safetensors-0.4.5-cp310-none-win_amd64.whl", hash = "sha256:e98ef5524f8b6620c8cdef97220c0b6a5c1cef69852fcd2f174bb96c2bb316b1"}, - {file = "safetensors-0.4.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:21f848d7aebd5954f92538552d6d75f7c1b4500f51664078b5b49720d180e47c"}, - {file = "safetensors-0.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb07000b19d41e35eecef9a454f31a8b4718a185293f0d0b1c4b61d6e4487971"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09dedf7c2fda934ee68143202acff6e9e8eb0ddeeb4cfc24182bef999efa9f42"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:59b77e4b7a708988d84f26de3ebead61ef1659c73dcbc9946c18f3b1786d2688"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d3bc83e14d67adc2e9387e511097f254bd1b43c3020440e708858c684cbac68"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39371fc551c1072976073ab258c3119395294cf49cdc1f8476794627de3130df"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6c19feda32b931cae0acd42748a670bdf56bee6476a046af20181ad3fee4090"}, - {file = "safetensors-0.4.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a659467495de201e2f282063808a41170448c78bada1e62707b07a27b05e6943"}, - {file = "safetensors-0.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bad5e4b2476949bcd638a89f71b6916fa9a5cae5c1ae7eede337aca2100435c0"}, - {file = "safetensors-0.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a3a315a6d0054bc6889a17f5668a73f94f7fe55121ff59e0a199e3519c08565f"}, - {file = "safetensors-0.4.5-cp311-none-win32.whl", hash = "sha256:a01e232e6d3d5cf8b1667bc3b657a77bdab73f0743c26c1d3c5dd7ce86bd3a92"}, - {file = "safetensors-0.4.5-cp311-none-win_amd64.whl", hash = "sha256:cbd39cae1ad3e3ef6f63a6f07296b080c951f24cec60188378e43d3713000c04"}, - {file = "safetensors-0.4.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:473300314e026bd1043cef391bb16a8689453363381561b8a3e443870937cc1e"}, - {file = "safetensors-0.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:801183a0f76dc647f51a2d9141ad341f9665602a7899a693207a82fb102cc53e"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1524b54246e422ad6fb6aea1ac71edeeb77666efa67230e1faf6999df9b2e27f"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3139098e3e8b2ad7afbca96d30ad29157b50c90861084e69fcb80dec7430461"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65573dc35be9059770808e276b017256fa30058802c29e1038eb1c00028502ea"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd33da8e9407559f8779c82a0448e2133737f922d71f884da27184549416bfed"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3685ce7ed036f916316b567152482b7e959dc754fcc4a8342333d222e05f407c"}, - {file = "safetensors-0.4.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dde2bf390d25f67908278d6f5d59e46211ef98e44108727084d4637ee70ab4f1"}, - {file = "safetensors-0.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7469d70d3de970b1698d47c11ebbf296a308702cbaae7fcb993944751cf985f4"}, - {file = "safetensors-0.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a6ba28118636a130ccbb968bc33d4684c48678695dba2590169d5ab03a45646"}, - {file = "safetensors-0.4.5-cp312-none-win32.whl", hash = "sha256:c859c7ed90b0047f58ee27751c8e56951452ed36a67afee1b0a87847d065eec6"}, - {file = "safetensors-0.4.5-cp312-none-win_amd64.whl", hash = "sha256:b5a8810ad6a6f933fff6c276eae92c1da217b39b4d8b1bc1c0b8af2d270dc532"}, - {file = "safetensors-0.4.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:25e5f8e2e92a74f05b4ca55686234c32aac19927903792b30ee6d7bd5653d54e"}, - {file = "safetensors-0.4.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:81efb124b58af39fcd684254c645e35692fea81c51627259cdf6d67ff4458916"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:585f1703a518b437f5103aa9cf70e9bd437cb78eea9c51024329e4fb8a3e3679"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4b99fbf72e3faf0b2f5f16e5e3458b93b7d0a83984fe8d5364c60aa169f2da89"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b17b299ca9966ca983ecda1c0791a3f07f9ca6ab5ded8ef3d283fff45f6bcd5f"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76ded72f69209c9780fdb23ea89e56d35c54ae6abcdec67ccb22af8e696e449a"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2783956926303dcfeb1de91a4d1204cd4089ab441e622e7caee0642281109db3"}, - {file = "safetensors-0.4.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d94581aab8c6b204def4d7320f07534d6ee34cd4855688004a4354e63b639a35"}, - {file = "safetensors-0.4.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:67e1e7cb8678bb1b37ac48ec0df04faf689e2f4e9e81e566b5c63d9f23748523"}, - {file = "safetensors-0.4.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:dbd280b07e6054ea68b0cb4b16ad9703e7d63cd6890f577cb98acc5354780142"}, - {file = "safetensors-0.4.5-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:77d9b228da8374c7262046a36c1f656ba32a93df6cc51cd4453af932011e77f1"}, - {file = "safetensors-0.4.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:500cac01d50b301ab7bb192353317035011c5ceeef0fca652f9f43c000bb7f8d"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75331c0c746f03158ded32465b7d0b0e24c5a22121743662a2393439c43a45cf"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:670e95fe34e0d591d0529e5e59fd9d3d72bc77b1444fcaa14dccda4f36b5a38b"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:098923e2574ff237c517d6e840acada8e5b311cb1fa226019105ed82e9c3b62f"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13ca0902d2648775089fa6a0c8fc9e6390c5f8ee576517d33f9261656f851e3f"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0032bedc869c56f8d26259fe39cd21c5199cd57f2228d817a0e23e8370af25"}, - {file = "safetensors-0.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4b15f51b4f8f2a512341d9ce3475cacc19c5fdfc5db1f0e19449e75f95c7dc8"}, - {file = "safetensors-0.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f6594d130d0ad933d885c6a7b75c5183cb0e8450f799b80a39eae2b8508955eb"}, - {file = "safetensors-0.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:60c828a27e852ded2c85fc0f87bf1ec20e464c5cd4d56ff0e0711855cc2e17f8"}, - {file = "safetensors-0.4.5-cp37-none-win32.whl", hash = "sha256:6d3de65718b86c3eeaa8b73a9c3d123f9307a96bbd7be9698e21e76a56443af5"}, - {file = "safetensors-0.4.5-cp37-none-win_amd64.whl", hash = "sha256:5a2d68a523a4cefd791156a4174189a4114cf0bf9c50ceb89f261600f3b2b81a"}, - {file = "safetensors-0.4.5-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:e7a97058f96340850da0601a3309f3d29d6191b0702b2da201e54c6e3e44ccf0"}, - {file = "safetensors-0.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:63bfd425e25f5c733f572e2246e08a1c38bd6f2e027d3f7c87e2e43f228d1345"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3664ac565d0e809b0b929dae7ccd74e4d3273cd0c6d1220c6430035befb678e"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:313514b0b9b73ff4ddfb4edd71860696dbe3c1c9dc4d5cc13dbd74da283d2cbf"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31fa33ee326f750a2f2134a6174773c281d9a266ccd000bd4686d8021f1f3dac"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09566792588d77b68abe53754c9f1308fadd35c9f87be939e22c623eaacbed6b"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309aaec9b66cbf07ad3a2e5cb8a03205663324fea024ba391594423d0f00d9fe"}, - {file = "safetensors-0.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:53946c5813b8f9e26103c5efff4a931cc45d874f45229edd68557ffb35ffb9f8"}, - {file = "safetensors-0.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:868f9df9e99ad1e7f38c52194063a982bc88fedc7d05096f4f8160403aaf4bd6"}, - {file = "safetensors-0.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9cc9449bd0b0bc538bd5e268221f0c5590bc5c14c1934a6ae359d44410dc68c4"}, - {file = "safetensors-0.4.5-cp38-none-win32.whl", hash = "sha256:83c4f13a9e687335c3928f615cd63a37e3f8ef072a3f2a0599fa09f863fb06a2"}, - {file = "safetensors-0.4.5-cp38-none-win_amd64.whl", hash = "sha256:b98d40a2ffa560653f6274e15b27b3544e8e3713a44627ce268f419f35c49478"}, - {file = "safetensors-0.4.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cf727bb1281d66699bef5683b04d98c894a2803442c490a8d45cd365abfbdeb2"}, - {file = "safetensors-0.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96f1d038c827cdc552d97e71f522e1049fef0542be575421f7684756a748e457"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:139fbee92570ecea774e6344fee908907db79646d00b12c535f66bc78bd5ea2c"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c36302c1c69eebb383775a89645a32b9d266878fab619819ce660309d6176c9b"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d641f5b8149ea98deb5ffcf604d764aad1de38a8285f86771ce1abf8e74c4891"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b4db6a61d968de73722b858038c616a1bebd4a86abe2688e46ca0cc2d17558f2"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b75a616e02f21b6f1d5785b20cecbab5e2bd3f6358a90e8925b813d557666ec1"}, - {file = "safetensors-0.4.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:788ee7d04cc0e0e7f944c52ff05f52a4415b312f5efd2ee66389fb7685ee030c"}, - {file = "safetensors-0.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87bc42bd04fd9ca31396d3ca0433db0be1411b6b53ac5a32b7845a85d01ffc2e"}, - {file = "safetensors-0.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4037676c86365a721a8c9510323a51861d703b399b78a6b4486a54a65a975fca"}, - {file = "safetensors-0.4.5-cp39-none-win32.whl", hash = "sha256:1500418454529d0ed5c1564bda376c4ddff43f30fce9517d9bee7bcce5a8ef50"}, - {file = "safetensors-0.4.5-cp39-none-win_amd64.whl", hash = "sha256:9d1a94b9d793ed8fe35ab6d5cea28d540a46559bafc6aae98f30ee0867000cab"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdadf66b5a22ceb645d5435a0be7a0292ce59648ca1d46b352f13cff3ea80410"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d42ffd4c2259f31832cb17ff866c111684c87bd930892a1ba53fed28370c918c"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd8a1f6d2063a92cd04145c7fd9e31a1c7d85fbec20113a14b487563fdbc0597"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:951d2fcf1817f4fb0ef0b48f6696688a4e852a95922a042b3f96aaa67eedc920"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ac85d9a8c1af0e3132371d9f2d134695a06a96993c2e2f0bbe25debb9e3f67a"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e3cec4a29eb7fe8da0b1c7988bc3828183080439dd559f720414450de076fcab"}, - {file = "safetensors-0.4.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:21742b391b859e67b26c0b2ac37f52c9c0944a879a25ad2f9f9f3cd61e7fda8f"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7db3006a4915151ce1913652e907cdede299b974641a83fbc092102ac41b644"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f68bf99ea970960a237f416ea394e266e0361895753df06e3e06e6ea7907d98b"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8158938cf3324172df024da511839d373c40fbfaa83e9abf467174b2910d7b4c"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:540ce6c4bf6b58cb0fd93fa5f143bc0ee341c93bb4f9287ccd92cf898cc1b0dd"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bfeaa1a699c6b9ed514bd15e6a91e74738b71125a9292159e3d6b7f0a53d2cde"}, - {file = "safetensors-0.4.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:01c8f00da537af711979e1b42a69a8ec9e1d7112f208e0e9b8a35d2c381085ef"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a0dd565f83b30f2ca79b5d35748d0d99dd4b3454f80e03dfb41f0038e3bdf180"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:023b6e5facda76989f4cba95a861b7e656b87e225f61811065d5c501f78cdb3f"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9633b663393d5796f0b60249549371e392b75a0b955c07e9c6f8708a87fc841f"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78dd8adfb48716233c45f676d6e48534d34b4bceb50162c13d1f0bdf6f78590a"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e8deb16c4321d61ae72533b8451ec4a9af8656d1c61ff81aa49f966406e4b68"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:52452fa5999dc50c4decaf0c53aa28371f7f1e0fe5c2dd9129059fbe1e1599c7"}, - {file = "safetensors-0.4.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d5f23198821e227cfc52d50fa989813513db381255c6d100927b012f0cfec63d"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f4beb84b6073b1247a773141a6331117e35d07134b3bb0383003f39971d414bb"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:68814d599d25ed2fdd045ed54d370d1d03cf35e02dce56de44c651f828fb9b7b"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b6453c54c57c1781292c46593f8a37254b8b99004c68d6c3ce229688931a22"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adaa9c6dead67e2dd90d634f89131e43162012479d86e25618e821a03d1eb1dc"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73e7d408e9012cd17511b382b43547850969c7979efc2bc353f317abaf23c84c"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:775409ce0fcc58b10773fdb4221ed1eb007de10fe7adbdf8f5e8a56096b6f0bc"}, - {file = "safetensors-0.4.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:834001bed193e4440c4a3950a31059523ee5090605c907c66808664c932b549c"}, - {file = "safetensors-0.4.5.tar.gz", hash = "sha256:d73de19682deabb02524b3d5d1f8b3aaba94c72f1bbfc7911b9b9d5d391c0310"}, + {file = "safetensors-0.5.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:45b6092997ceb8aa3801693781a71a99909ab9cc776fbc3fa9322d29b1d3bef2"}, + {file = "safetensors-0.5.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6d0d6a8ee2215a440e1296b843edf44fd377b055ba350eaba74655a2fe2c4bae"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86016d40bcaa3bcc9a56cd74d97e654b5f4f4abe42b038c71e4f00a089c4526c"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:990833f70a5f9c7d3fc82c94507f03179930ff7d00941c287f73b6fcbf67f19e"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dfa7c2f3fe55db34eba90c29df94bcdac4821043fc391cb5d082d9922013869"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46ff2116150ae70a4e9c490d2ab6b6e1b1b93f25e520e540abe1b81b48560c3a"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab696dfdc060caffb61dbe4066b86419107a24c804a4e373ba59be699ebd8d5"}, + {file = "safetensors-0.5.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03c937100f38c9ff4c1507abea9928a6a9b02c9c1c9c3609ed4fb2bf413d4975"}, + {file = "safetensors-0.5.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a00e737948791b94dad83cf0eafc09a02c4d8c2171a239e8c8572fe04e25960e"}, + {file = "safetensors-0.5.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:d3a06fae62418ec8e5c635b61a8086032c9e281f16c63c3af46a6efbab33156f"}, + {file = "safetensors-0.5.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1506e4c2eda1431099cebe9abf6c76853e95d0b7a95addceaa74c6019c65d8cf"}, + {file = "safetensors-0.5.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5c5b5d9da594f638a259fca766046f44c97244cc7ab8bef161b3e80d04becc76"}, + {file = "safetensors-0.5.2-cp38-abi3-win32.whl", hash = "sha256:fe55c039d97090d1f85277d402954dd6ad27f63034fa81985a9cc59655ac3ee2"}, + {file = "safetensors-0.5.2-cp38-abi3-win_amd64.whl", hash = "sha256:78abdddd03a406646107f973c7843276e7b64e5e32623529dc17f3d94a20f589"}, + {file = "safetensors-0.5.2.tar.gz", hash = "sha256:cb4a8d98ba12fa016f4241932b1fc5e702e5143f5374bba0bbcf7ddc1c4cf2b8"}, ] [package.extras] @@ -4382,7 +4520,7 @@ jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "safetensors[num mlx = ["mlx (>=0.0.9)"] numpy = ["numpy (>=1.21.6)"] paddlepaddle = ["paddlepaddle (>=2.4.1)", "safetensors[numpy]"] -pinned-tf = ["safetensors[numpy]", "tensorflow (==2.11.0)"] +pinned-tf = ["safetensors[numpy]", "tensorflow (==2.18.0)"] quality = ["black (==22.3)", "click (==8.0.4)", "flake8 (>=3.8.3)", "isort (>=5.5.4)"] tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"] testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] @@ -4452,35 +4590,60 @@ files = [ [[package]] name = "setuptools" -version = "75.2.0" +version = "75.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, + {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "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)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "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)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "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", "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)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +[[package]] +name = "smart-open" +version = "7.1.0" +description = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)" +optional = true +python-versions = "<4.0,>=3.7" +files = [ + {file = "smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b"}, + {file = "smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba"}, +] + +[package.dependencies] +wrapt = "*" + +[package.extras] +all = ["azure-common", "azure-core", "azure-storage-blob", "boto3", "google-cloud-storage (>=2.6.0)", "paramiko", "requests", "zstandard"] +azure = ["azure-common", "azure-core", "azure-storage-blob"] +gcs = ["google-cloud-storage (>=2.6.0)"] +http = ["requests"] +s3 = ["boto3"] +ssh = ["paramiko"] +test = ["awscli", "azure-common", "azure-core", "azure-storage-blob", "boto3", "google-cloud-storage (>=2.6.0)", "moto[server]", "numpy", "paramiko", "pyopenssl", "pytest", "pytest-benchmark", "pytest-rerunfailures", "requests", "responses", "zstandard"] +webhdfs = ["requests"] +zst = ["zstandard"] + [[package]] name = "sniffio" version = "1.3.1" @@ -4494,13 +4657,13 @@ files = [ [[package]] name = "starlette" -version = "0.40.0" +version = "0.41.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.40.0-py3-none-any.whl", hash = "sha256:c494a22fae73805376ea6bf88439783ecfba9aac88a43911b48c653437e784c4"}, - {file = "starlette-0.40.0.tar.gz", hash = "sha256:1a3139688fb298ce5e2d661d37046a66ad996ce94be4d4983be019a23a04ea35"}, + {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, + {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, ] [package.dependencies] @@ -4541,6 +4704,26 @@ files = [ [package.extras] widechars = ["wcwidth"] +[[package]] +name = "textual" +version = "1.0.0" +description = "Modern Text User Interface framework" +optional = true +python-versions = "<4.0.0,>=3.8.1" +files = [ + {file = "textual-1.0.0-py3-none-any.whl", hash = "sha256:2d4a701781c05104925e463ae370c630567c70c2880e92ab838052e3e23c986f"}, + {file = "textual-1.0.0.tar.gz", hash = "sha256:bec9fe63547c1c552569d1b75d309038b7d456c03f86dfa3706ddb099b151399"}, +] + +[package.dependencies] +markdown-it-py = {version = ">=2.1.0", extras = ["linkify", "plugins"]} +platformdirs = ">=3.6.0,<5" +rich = ">=13.3.3" +typing-extensions = ">=4.4.0,<5.0.0" + +[package.extras] +syntax = ["tree-sitter (>=0.23.0)", "tree-sitter-bash (>=0.23.0)", "tree-sitter-css (>=0.23.0)", "tree-sitter-go (>=0.23.0)", "tree-sitter-html (>=0.23.0)", "tree-sitter-java (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.24.0)", "tree-sitter-markdown (>=0.3.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-regex (>=0.24.0)", "tree-sitter-rust (>=0.23.0)", "tree-sitter-sql (>=0.3.0)", "tree-sitter-toml (>=0.6.0)", "tree-sitter-xml (>=0.7.0)", "tree-sitter-yaml (>=0.6.0)"] + [[package]] name = "tiktoken" version = "0.7.0" @@ -4606,111 +4789,26 @@ files = [ [[package]] name = "tokenizers" -version = "0.20.1" +version = "0.21.0" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "tokenizers-0.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:439261da7c0a5c88bda97acb284d49fbdaf67e9d3b623c0bfd107512d22787a9"}, - {file = "tokenizers-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03dae629d99068b1ea5416d50de0fea13008f04129cc79af77a2a6392792d93c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b61f561f329ffe4b28367798b89d60c4abf3f815d37413b6352bc6412a359867"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec870fce1ee5248a10be69f7a8408a234d6f2109f8ea827b4f7ecdbf08c9fd15"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d388d1ea8b7447da784e32e3b86a75cce55887e3b22b31c19d0b186b1c677800"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:299c85c1d21135bc01542237979bf25c32efa0d66595dd0069ae259b97fb2dbe"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96f6c14c9752bb82145636b614d5a78e9cde95edfbe0a85dad0dd5ddd6ec95c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc9e95ad49c932b80abfbfeaf63b155761e695ad9f8a58c52a47d962d76e310f"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f22dee205329a636148c325921c73cf3e412e87d31f4d9c3153b302a0200057b"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2ffd9a8895575ac636d44500c66dffaef133823b6b25067604fa73bbc5ec09d"}, - {file = "tokenizers-0.20.1-cp310-none-win32.whl", hash = "sha256:2847843c53f445e0f19ea842a4e48b89dd0db4e62ba6e1e47a2749d6ec11f50d"}, - {file = "tokenizers-0.20.1-cp310-none-win_amd64.whl", hash = "sha256:f9aa93eacd865f2798b9e62f7ce4533cfff4f5fbd50c02926a78e81c74e432cd"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4a717dcb08f2dabbf27ae4b6b20cbbb2ad7ed78ce05a829fae100ff4b3c7ff15"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f84dad1ff1863c648d80628b1b55353d16303431283e4efbb6ab1af56a75832"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:929c8f3afa16a5130a81ab5079c589226273ec618949cce79b46d96e59a84f61"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d10766473954397e2d370f215ebed1cc46dcf6fd3906a2a116aa1d6219bfedc3"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9300fac73ddc7e4b0330acbdda4efaabf74929a4a61e119a32a181f534a11b47"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ecaf7b0e39caeb1aa6dd6e0975c405716c82c1312b55ac4f716ef563a906969"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5170be9ec942f3d1d317817ced8d749b3e1202670865e4fd465e35d8c259de83"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f1ae08fa9aea5891cbd69df29913e11d3841798e0bfb1ff78b78e4e7ea0a4"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee86d4095d3542d73579e953c2e5e07d9321af2ffea6ecc097d16d538a2dea16"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:86dcd08da163912e17b27bbaba5efdc71b4fbffb841530fdb74c5707f3c49216"}, - {file = "tokenizers-0.20.1-cp311-none-win32.whl", hash = "sha256:9af2dc4ee97d037bc6b05fa4429ddc87532c706316c5e11ce2f0596dfcfa77af"}, - {file = "tokenizers-0.20.1-cp311-none-win_amd64.whl", hash = "sha256:899152a78b095559c287b4c6d0099469573bb2055347bb8154db106651296f39"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:407ab666b38e02228fa785e81f7cf79ef929f104bcccf68a64525a54a93ceac9"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f13a2d16032ebc8bd812eb8099b035ac65887d8f0c207261472803b9633cf3e"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98eee4dca22849fbb56a80acaa899eec5b72055d79637dd6aa15d5e4b8628c9"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47c1bcdd61e61136087459cb9e0b069ff23b5568b008265e5cbc927eae3387ce"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128c1110e950534426e2274837fc06b118ab5f2fa61c3436e60e0aada0ccfd67"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2e2d47a819d2954f2c1cd0ad51bb58ffac6f53a872d5d82d65d79bf76b9896d"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdd67a0e3503a9a7cf8bc5a4a49cdde5fa5bada09a51e4c7e1c73900297539bd"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b93d2e26d04da337ac407acec8b5d081d8d135e3e5066a88edd5bdb5aff89"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0c6a796ddcd9a19ad13cf146997cd5895a421fe6aec8fd970d69f9117bddb45c"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3ea919687aa7001a8ff1ba36ac64f165c4e89035f57998fa6cedcfd877be619d"}, - {file = "tokenizers-0.20.1-cp312-none-win32.whl", hash = "sha256:6d3ac5c1f48358ffe20086bf065e843c0d0a9fce0d7f0f45d5f2f9fba3609ca5"}, - {file = "tokenizers-0.20.1-cp312-none-win_amd64.whl", hash = "sha256:b0874481aea54a178f2bccc45aa2d0c99cd3f79143a0948af6a9a21dcc49173b"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:96af92e833bd44760fb17f23f402e07a66339c1dcbe17d79a9b55bb0cc4f038e"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:65f34e5b731a262dfa562820818533c38ce32a45864437f3d9c82f26c139ca7f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17f98fccb5c12ab1ce1f471731a9cd86df5d4bd2cf2880c5a66b229802d96145"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8c0fc3542cf9370bf92c932eb71bdeb33d2d4aeeb4126d9fd567b60bd04cb30"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b39356df4575d37f9b187bb623aab5abb7b62c8cb702867a1768002f814800c"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfdad27b0e50544f6b838895a373db6114b85112ba5c0cefadffa78d6daae563"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:094663dd0e85ee2e573126918747bdb40044a848fde388efb5b09d57bc74c680"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e4cf033a2aa207d7ac790e91adca598b679999710a632c4a494aab0fc3a1b2"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9310951c92c9fb91660de0c19a923c432f110dbfad1a2d429fbc44fa956bf64f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:05e41e302c315bd2ed86c02e917bf03a6cf7d2f652c9cee1a0eb0d0f1ca0d32c"}, - {file = "tokenizers-0.20.1-cp37-none-win32.whl", hash = "sha256:212231ab7dfcdc879baf4892ca87c726259fa7c887e1688e3f3cead384d8c305"}, - {file = "tokenizers-0.20.1-cp37-none-win_amd64.whl", hash = "sha256:896195eb9dfdc85c8c052e29947169c1fcbe75a254c4b5792cdbd451587bce85"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:741fb22788482d09d68e73ece1495cfc6d9b29a06c37b3df90564a9cfa688e6d"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10be14ebd8082086a342d969e17fc2d6edc856c59dbdbddd25f158fa40eaf043"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:514cf279b22fa1ae0bc08e143458c74ad3b56cd078b319464959685a35c53d5e"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a647c5b7cb896d6430cf3e01b4e9a2d77f719c84cefcef825d404830c2071da2"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cdf379219e1e1dd432091058dab325a2e6235ebb23e0aec8d0508567c90cd01"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ba72260449e16c4c2f6f3252823b059fbf2d31b32617e582003f2b18b415c39"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:910b96ed87316e4277b23c7bcaf667ce849c7cc379a453fa179e7e09290eeb25"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53975a6694428a0586534cc1354b2408d4e010a3103117f617cbb550299797c"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:07c4b7be58da142b0730cc4e5fd66bb7bf6f57f4986ddda73833cd39efef8a01"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b605c540753e62199bf15cf69c333e934077ef2350262af2ccada46026f83d1c"}, - {file = "tokenizers-0.20.1-cp38-none-win32.whl", hash = "sha256:88b3bc76ab4db1ab95ead623d49c95205411e26302cf9f74203e762ac7e85685"}, - {file = "tokenizers-0.20.1-cp38-none-win_amd64.whl", hash = "sha256:d412a74cf5b3f68a90c615611a5aa4478bb303d1c65961d22db45001df68afcb"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a25dcb2f41a0a6aac31999e6c96a75e9152fa0127af8ece46c2f784f23b8197a"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a12c3cebb8c92e9c35a23ab10d3852aee522f385c28d0b4fe48c0b7527d59762"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02e18da58cf115b7c40de973609c35bde95856012ba42a41ee919c77935af251"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f326a1ac51ae909b9760e34671c26cd0dfe15662f447302a9d5bb2d872bab8ab"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b4872647ea6f25224e2833b044b0b19084e39400e8ead3cfe751238b0802140"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce6238a3311bb8e4c15b12600927d35c267b92a52c881ef5717a900ca14793f7"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57b7a8880b208866508b06ce365dc631e7a2472a3faa24daa430d046fb56c885"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a908c69c2897a68f412aa05ba38bfa87a02980df70f5a72fa8490479308b1f2d"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:da1001aa46f4490099c82e2facc4fbc06a6a32bf7de3918ba798010954b775e0"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c097390e2f0ed0a5c5d569e6669dd4e9fff7b31c6a5ce6e9c66a61687197de"}, - {file = "tokenizers-0.20.1-cp39-none-win32.whl", hash = "sha256:3d4d218573a3d8b121a1f8c801029d70444ffb6d8f129d4cca1c7b672ee4a24c"}, - {file = "tokenizers-0.20.1-cp39-none-win_amd64.whl", hash = "sha256:37d1e6f616c84fceefa7c6484a01df05caf1e207669121c66213cb5b2911d653"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48689da7a395df41114f516208d6550e3e905e1239cc5ad386686d9358e9cef0"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:712f90ea33f9bd2586b4a90d697c26d56d0a22fd3c91104c5858c4b5b6489a79"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:359eceb6a620c965988fc559cebc0a98db26713758ec4df43fb76d41486a8ed5"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d3caf244ce89d24c87545aafc3448be15870096e796c703a0d68547187192e1"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03b03cf8b9a32254b1bf8a305fb95c6daf1baae0c1f93b27f2b08c9759f41dee"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:218e5a3561561ea0f0ef1559c6d95b825308dbec23fb55b70b92589e7ff2e1e8"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:08aaa0d72bb65058e8c4b0455f61b840b156c557e2aca57627056624c3a93976"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:998700177b45f70afeb206ad22c08d9e5f3a80639dae1032bf41e8cbc4dada4b"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f7fbd3c2c38b179556d879edae442b45f68312019c3a6013e56c3947a4e648"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e87fca4f6bbf5cc67481b562147fe932f73d5602734de7dd18a8f2eee9c6dd"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:956f21d359ae29dd51ca5726d2c9a44ffafa041c623f5aa33749da87cfa809b9"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1fbbaf17a393c78d8aedb6a334097c91cb4119a9ced4764ab8cfdc8d254dc9f9"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ebe63e31f9c1a970c53866d814e35ec2ec26fda03097c486f82f3891cee60830"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:81970b80b8ac126910295f8aab2d7ef962009ea39e0d86d304769493f69aaa1e"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130e35e76f9337ed6c31be386e75d4925ea807055acf18ca1a9b0eec03d8fe23"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd28a8614f5c82a54ab2463554e84ad79526c5184cf4573bbac2efbbbcead457"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9041ee665d0fa7f5c4ccf0f81f5e6b7087f797f85b143c094126fc2611fec9d0"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:62eb9daea2a2c06bcd8113a5824af8ef8ee7405d3a71123ba4d52c79bb3d9f1a"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f861889707b54a9ab1204030b65fd6c22bdd4a95205deec7994dc22a8baa2ea4"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:89d5c337d74ea6e5e7dc8af124cf177be843bbb9ca6e58c01f75ea103c12c8a9"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0b7f515c83397e73292accdbbbedc62264e070bae9682f06061e2ddce67cacaf"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0305fc1ec6b1e5052d30d9c1d5c807081a7bd0cae46a33d03117082e91908c"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc611e6ac0fa00a41de19c3bf6391a05ea201d2d22b757d63f5491ec0e67faa"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5ffe0d7f7bfcfa3b2585776ecf11da2e01c317027c8573c78ebcb8985279e23"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e7edb8ec12c100d5458d15b1e47c0eb30ad606a05641f19af7563bc3d1608c14"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:de291633fb9303555793cc544d4a86e858da529b7d0b752bcaf721ae1d74b2c9"}, - {file = "tokenizers-0.20.1.tar.gz", hash = "sha256:84edcc7cdeeee45ceedb65d518fffb77aec69311c9c8e30f77ad84da3025f002"}, + {file = "tokenizers-0.21.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2"}, + {file = "tokenizers-0.21.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b177fb54c4702ef611de0c069d9169f0004233890e0c4c5bd5508ae05abf193"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b43779a269f4629bebb114e19c3fca0223296ae9fea8bb9a7a6c6fb0657ff8e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aeb255802be90acfd363626753fda0064a8df06031012fe7d52fd9a905eb00e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8b09dbeb7a8d73ee204a70f94fc06ea0f17dcf0844f16102b9f414f0b7463ba"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:400832c0904f77ce87c40f1a8a27493071282f785724ae62144324f171377273"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84ca973b3a96894d1707e189c14a774b701596d579ffc7e69debfc036a61a04"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:eb7202d231b273c34ec67767378cd04c767e967fda12d4a9e36208a34e2f137e"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:089d56db6782a73a27fd8abf3ba21779f5b85d4a9f35e3b493c7bbcbbf0d539b"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:c87ca3dc48b9b1222d984b6b7490355a6fdb411a2d810f6f05977258400ddb74"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4145505a973116f91bc3ac45988a92e618a6f83eb458f49ea0790df94ee243ff"}, + {file = "tokenizers-0.21.0-cp39-abi3-win32.whl", hash = "sha256:eb1702c2f27d25d9dd5b389cc1f2f51813e99f8ca30d9e25348db6585a97e24a"}, + {file = "tokenizers-0.21.0-cp39-abi3-win_amd64.whl", hash = "sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c"}, + {file = "tokenizers-0.21.0.tar.gz", hash = "sha256:ee0894bf311b75b0c03079f33859ae4b2334d675d4e93f5a4132e1eae2834fe4"}, ] [package.dependencies] @@ -4723,42 +4821,69 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"] [[package]] name = "tomli" -version = "2.0.2" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {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 = "torch" -version = "2.4.0" +version = "2.5.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = false python-versions = ">=3.8.0" files = [ - {file = "torch-2.4.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:4ed94583e244af51d6a8d28701ca5a9e02d1219e782f5a01dd401f90af17d8ac"}, - {file = "torch-2.4.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:c4ca297b7bd58b506bfd6e78ffd14eb97c0e7797dcd7965df62f50bb575d8954"}, - {file = "torch-2.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:2497cbc7b3c951d69b276ca51fe01c2865db67040ac67f5fc20b03e41d16ea4a"}, - {file = "torch-2.4.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:685418ab93730efbee71528821ff54005596970dd497bf03c89204fb7e3f71de"}, - {file = "torch-2.4.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:e743adadd8c8152bb8373543964551a7cb7cc20ba898dc8f9c0cdbe47c283de0"}, - {file = "torch-2.4.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:7334325c0292cbd5c2eac085f449bf57d3690932eac37027e193ba775703c9e6"}, - {file = "torch-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:97730014da4c57ffacb3c09298c6ce05400606e890bd7a05008d13dd086e46b1"}, - {file = "torch-2.4.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:f169b4ea6dc93b3a33319611fcc47dc1406e4dd539844dcbd2dec4c1b96e166d"}, - {file = "torch-2.4.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:997084a0f9784d2a89095a6dc67c7925e21bf25dea0b3d069b41195016ccfcbb"}, - {file = "torch-2.4.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:bc3988e8b36d1e8b998d143255d9408d8c75da4ab6dd0dcfd23b623dfb0f0f57"}, - {file = "torch-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:3374128bbf7e62cdaed6c237bfd39809fbcfaa576bee91e904706840c3f2195c"}, - {file = "torch-2.4.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:91aaf00bfe1ffa44dc5b52809d9a95129fca10212eca3ac26420eb11727c6288"}, - {file = "torch-2.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cc30457ea5489c62747d3306438af00c606b509d78822a88f804202ba63111ed"}, - {file = "torch-2.4.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a046491aaf96d1215e65e1fa85911ef2ded6d49ea34c8df4d0638879f2402eef"}, - {file = "torch-2.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:688eec9240f3ce775f22e1e1a5ab9894f3d5fe60f3f586deb7dbd23a46a83916"}, - {file = "torch-2.4.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:3af4de2a618fb065e78404c4ba27a818a7b7957eaeff28c6c66ce7fb504b68b8"}, - {file = "torch-2.4.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:618808d3f610d5f180e47a697d4ec90b810953bb1e020f424b2ac7fb0884b545"}, - {file = "torch-2.4.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ed765d232d23566052ba83632ec73a4fccde00b4c94ad45d63b471b09d63b7a7"}, - {file = "torch-2.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2feb98ac470109472fb10dfef38622a7ee08482a16c357863ebc7bc7db7c8f7"}, - {file = "torch-2.4.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:8940fc8b97a4c61fdb5d46a368f21f4a3a562a17879e932eb51a5ec62310cb31"}, + {file = "torch-2.5.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:71328e1bbe39d213b8721678f9dcac30dfc452a46d586f1d514a6aa0a99d4744"}, + {file = "torch-2.5.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:34bfa1a852e5714cbfa17f27c49d8ce35e1b7af5608c4bc6e81392c352dbc601"}, + {file = "torch-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:32a037bd98a241df6c93e4c789b683335da76a2ac142c0973675b715102dc5fa"}, + {file = "torch-2.5.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:23d062bf70776a3d04dbe74db950db2a5245e1ba4f27208a87f0d743b0d06e86"}, + {file = "torch-2.5.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:de5b7d6740c4b636ef4db92be922f0edc425b65ed78c5076c43c42d362a45457"}, + {file = "torch-2.5.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:340ce0432cad0d37f5a31be666896e16788f1adf8ad7be481196b503dad675b9"}, + {file = "torch-2.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:603c52d2fe06433c18b747d25f5c333f9c1d58615620578c326d66f258686f9a"}, + {file = "torch-2.5.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:31f8c39660962f9ae4eeec995e3049b5492eb7360dd4f07377658ef4d728fa4c"}, + {file = "torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ed231a4b3a5952177fafb661213d690a72caaad97d5824dd4fc17ab9e15cec03"}, + {file = "torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:3f4b7f10a247e0dcd7ea97dc2d3bfbfc90302ed36d7f3952b0008d0df264e697"}, + {file = "torch-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:73e58e78f7d220917c5dbfad1a40e09df9929d3b95d25e57d9f8558f84c9a11c"}, + {file = "torch-2.5.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:8c712df61101964eb11910a846514011f0b6f5920c55dbf567bff8a34163d5b1"}, + {file = "torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:9b61edf3b4f6e3b0e0adda8b3960266b9009d02b37555971f4d1c8f7a05afed7"}, + {file = "torch-2.5.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1f3b7fb3cf7ab97fae52161423f81be8c6b8afac8d9760823fd623994581e1a3"}, + {file = "torch-2.5.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7974e3dce28b5a21fb554b73e1bc9072c25dde873fa00d54280861e7a009d7dc"}, + {file = "torch-2.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:46c817d3ea33696ad3b9df5e774dba2257e9a4cd3c4a3afbf92f6bb13ac5ce2d"}, + {file = "torch-2.5.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:8046768b7f6d35b85d101b4b38cba8aa2f3cd51952bc4c06a49580f2ce682291"}, ] [package.dependencies] @@ -4766,63 +4891,56 @@ filelock = "*" fsspec = "*" jinja2 = "*" networkx = "*" -nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cublas-cu12 = {version = "12.4.5.8", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} nvidia-cudnn-cu12 = {version = "9.1.0.70", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.20.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -sympy = "*" -triton = {version = "3.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.13\""} +nvidia-cufft-cu12 = {version = "11.2.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.5.147", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.6.1.9", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.3.1.170", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.21.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} +sympy = {version = "1.13.1", markers = "python_version >= \"3.9\""} +triton = {version = "3.1.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.13\""} typing-extensions = ">=4.8.0" [package.extras] opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.11.0)"] +optree = ["optree (>=0.12.0)"] [[package]] name = "torchvision" -version = "0.19.0" +version = "0.20.1" description = "image and video datasets and models for torch deep learning" optional = true python-versions = ">=3.8" files = [ - {file = "torchvision-0.19.0-1-cp310-cp310-win_amd64.whl", hash = "sha256:6ed066aae5c50465d7c4761357aefe5dbd2eb7075a33ab8c14b352fc2353ad4c"}, - {file = "torchvision-0.19.0-1-cp311-cp311-win_amd64.whl", hash = "sha256:6b1bce2e4c003d890a18f14ff289528707d918e38539ff890ef02aa31dae1b56"}, - {file = "torchvision-0.19.0-1-cp312-cp312-win_amd64.whl", hash = "sha256:13aee7a46e049c8c1e7d35a0394b0587a7e62ff3d1a822cd2bbbacb675ac4a09"}, - {file = "torchvision-0.19.0-1-cp38-cp38-win_amd64.whl", hash = "sha256:2acc436d043d4f81b3bc6929cbfa4ef1cdae4d8a0b04ec72ec30a497e9a38179"}, - {file = "torchvision-0.19.0-1-cp39-cp39-win_amd64.whl", hash = "sha256:b5f70f5a8bd9c8b00a076bf466b39b5cd679ef62587c47cc048adb04d9c5f155"}, - {file = "torchvision-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec874ef85dcb24c69e600f6e276af892c80cde3ffdaeb7275efda463242bc2a8"}, - {file = "torchvision-0.19.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:106842b1e475b14d9a04ee0d6f5477d43100e3bb78e9d31e37422384d0d84179"}, - {file = "torchvision-0.19.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d467d434005fd05a227a2ba7af4c591bb67e6d4a97bbd06eda8da83f43e9fd07"}, - {file = "torchvision-0.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:f77ac31f7337d0f6f4b58e65582c6c93b9d9eeec7dfd7478896b5cdc19a2d60d"}, - {file = "torchvision-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbf3aa71a3899244fc884303ed3c4604a160824fefac77e82317a5463efc1d9b"}, - {file = "torchvision-0.19.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:ec4162dc71d9db7f0b51d0f92491929c1419605ff436e1305e50de13504a1c30"}, - {file = "torchvision-0.19.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:4e6aa4fa3f0bc3599fa071c149e651a3e6bdd67c9161794478f9f91471c406a2"}, - {file = "torchvision-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac5525d5cc09e425b5cf5752ecf66eefbbbd8c8cd945198ce35eb01a694e6069"}, - {file = "torchvision-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c09ef8ed184fa877f6251b620226e74f682b8f1d6b341456428d4955b8d9c670"}, - {file = "torchvision-0.19.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:02f1dd5cfc897957535b41b0258ec452d30de044e20c2de2c75869f7708e7656"}, - {file = "torchvision-0.19.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:be0f27a28b8e9f2ae98a31af34a4bdd2a5bf154d92bd73a5797c8d2156fb3ab6"}, - {file = "torchvision-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6ba7756f75c80212e51d3576f85ea204589e0c16efdb9b835dd677bc8929a67"}, - {file = "torchvision-0.19.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:854e967a16a9409e941b5bbe5aa357b23f7158bccb9de35ae20fd4945f05ecd1"}, - {file = "torchvision-0.19.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d9afb8a3c3ce99a161a64c2a3b91cb545632a72118053cbfb84e87a02a8dcd02"}, - {file = "torchvision-0.19.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:079a696e0b2cb52e4be30afa8e9b3d7d280f02a2b5ffedd7e821fa1efd1a5a8d"}, - {file = "torchvision-0.19.0-cp38-cp38-win_amd64.whl", hash = "sha256:aaa338ff3a55a8c0f94e0e64eff6fe2af1fc933a95fd43812760e72ea66e986b"}, - {file = "torchvision-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd1279571d4b68d5a53d9b7a35aedf91c4cb1e0b08099f6a1effa7b25b8c95e7"}, - {file = "torchvision-0.19.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d54b5e19b7ebebca7d0b08497b4c6335264cad04c94c05fa35988d9e9eed0c4"}, - {file = "torchvision-0.19.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5f9a598dcf82bdfc8e4436ce74763b3877dabec3b33f94613b94ede13e3e4dee"}, - {file = "torchvision-0.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:ec1281c10402234d470bfd4d53663d81f4364f293b2f8fe24d4a7a1adc78c90c"}, + {file = "torchvision-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4878fefb96ef293d06c27210918adc83c399d9faaf34cda5a63e129f772328f1"}, + {file = "torchvision-0.20.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8ffbdf8bf5b30eade22d459f5a313329eeadb20dc75efa142987b53c007098c3"}, + {file = "torchvision-0.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:75f8a4d51a593c4bab6c9bf7d75bdd88691b00a53b07656678bc55a3a753dd73"}, + {file = "torchvision-0.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:22c2fa44e20eb404b85e42b22b453863a14b0927d25e550fd4f84eea97fa5b39"}, + {file = "torchvision-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:344b339e15e6bbb59ee0700772616d0afefd209920c762b1604368d8c3458322"}, + {file = "torchvision-0.20.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:86f6523dee420000fe14c3527f6c8e0175139fda7d995b187f54a0b0ebec7eb6"}, + {file = "torchvision-0.20.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:a40d766345927639da322c693934e5f91b1ba2218846c7104b868dea2314ce8e"}, + {file = "torchvision-0.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:5b501d5c04b034d2ecda96a31ed050e383cf8201352e4c9276ca249cbecfded0"}, + {file = "torchvision-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1a31256ff945d64f006bb306813a7c95a531fe16bfb2535c837dd4c104533d7a"}, + {file = "torchvision-0.20.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:17cd78adddf81dac57d7dccc9277a4d686425b1c55715f308769770cb26cad5c"}, + {file = "torchvision-0.20.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:9f853ba4497ac4691815ad41b523ee23cf5ba4f87b1ce869d704052e233ca8b7"}, + {file = "torchvision-0.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:4a330422c36dbfc946d3a6c1caec3489db07ecdf3675d83369adb2e5a0ca17c4"}, + {file = "torchvision-0.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2cd58406978b813188cf4e9135b218775b57e0bb86d4a88f0339874b8a224819"}, + {file = "torchvision-0.20.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:408766b2f0ada9e1bc880d12346cec9638535af5df6459ba9ac4ce5c46402f91"}, + {file = "torchvision-0.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:abcb8005de8dc393dbd1310ecb669dc68ab664b9107af6d698a6341d1d3f2c3c"}, + {file = "torchvision-0.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:ea9678163bbf19568f4f959d927f3751eeb833cc8eac949de507edde38c1fc9f"}, ] [package.dependencies] numpy = "*" pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" -torch = "2.4.0" +torch = "2.5.1" [package.extras] gdown = ["gdown (>=4.7.3)"] @@ -4830,59 +4948,60 @@ scipy = ["scipy"] [[package]] name = "tqdm" -version = "4.66.6" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.6-py3-none-any.whl", hash = "sha256:223e8b5359c2efc4b30555531f09e9f2f3589bcd7fdd389271191031b49b7a63"}, - {file = "tqdm-4.66.6.tar.gz", hash = "sha256:4bdd694238bef1485ce839d67967ab50af8f9272aab687c0d7702a01da0be090"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] [[package]] name = "transformers" -version = "4.46.2" +version = "4.47.1" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "transformers-4.46.2-py3-none-any.whl", hash = "sha256:c921f4406b78e6518c97b618c5acd1cf8a4f2315b6b727f4bf9e01496eef849c"}, - {file = "transformers-4.46.2.tar.gz", hash = "sha256:3d85410881e1c074be767877bf33c83231ec11529f274a6044ecb20c157ba14e"}, + {file = "transformers-4.47.1-py3-none-any.whl", hash = "sha256:d2f5d19bb6283cd66c893ec7e6d931d6370bbf1cc93633326ff1f41a40046c9c"}, + {file = "transformers-4.47.1.tar.gz", hash = "sha256:6c29c05a5f595e278481166539202bf8641281536df1c42357ee58a45d0a564a"}, ] [package.dependencies] filelock = "*" -huggingface-hub = ">=0.23.2,<1.0" +huggingface-hub = ">=0.24.0,<1.0" numpy = ">=1.17" packaging = ">=20.0" pyyaml = ">=5.1" regex = "!=2019.12.17" requests = "*" safetensors = ">=0.4.1" -tokenizers = ">=0.20,<0.21" +tokenizers = ">=0.21,<0.22" tqdm = ">=4.27" [package.extras] accelerate = ["accelerate (>=0.26.0)"] agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch"] -all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision"] audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] benchmark = ["optimum-benchmark (>=0.3.0)"] codecarbon = ["codecarbon (==1.2.0)"] deepspeed = ["accelerate (>=0.26.0)", "deepspeed (>=0.9.3)"] deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk (<=3.8.1)", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] -dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] -dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.20,<0.21)", "urllib3 (<2.0.0)"] -dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "libcst", "librosa", "nltk (<=3.8.1)", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.21,<0.22)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "libcst", "librosa", "nltk (<=3.8.1)", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] ftfy = ["ftfy"] @@ -4908,27 +5027,27 @@ tf = ["keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow (>2.9,< tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] tiktoken = ["blobfile", "tiktoken"] -timm = ["timm (<=0.9.16)"] -tokenizers = ["tokenizers (>=0.20,<0.21)"] +timm = ["timm (<=1.0.11)"] +tokenizers = ["tokenizers (>=0.21,<0.22)"] torch = ["accelerate (>=0.26.0)", "torch"] torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] -torchhub = ["filelock", "huggingface-hub (>=0.23.2,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.20,<0.21)", "torch", "tqdm (>=4.27)"] +torchhub = ["filelock", "huggingface-hub (>=0.24.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.21,<0.22)", "torch", "tqdm (>=4.27)"] video = ["av (==9.2.0)"] vision = ["Pillow (>=10.0.1,<=15.0)"] [[package]] name = "triton" -version = "3.0.0" +version = "3.1.0" description = "A language and compiler for custom Deep Learning operations" optional = false python-versions = "*" files = [ - {file = "triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a"}, - {file = "triton-3.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ce8520437c602fb633f1324cc3871c47bee3b67acf9756c1a66309b60e3216c"}, - {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, - {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, - {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, + {file = "triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8"}, + {file = "triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f34f6e7885d1bf0eaaf7ba875a5f0ce6f3c13ba98f9503651c1e6dc6757ed5c"}, + {file = "triton-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8182f42fd8080a7d39d666814fa36c5e30cc00ea7eeeb1a2983dbb4c99a0fdc"}, + {file = "triton-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dadaca7fc24de34e180271b5cf864c16755702e9f63a16f62df714a8099126a"}, + {file = "triton-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aafa9a20cd0d9fee523cd4504aa7131807a864cd77dcf6efe7e981f18b8c6c11"}, ] [package.dependencies] @@ -4961,6 +5080,20 @@ files = [ {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] +[[package]] +name = "uc-micro-py" +version = "1.0.3" +description = "Micro subset of unicode data files for linkify-it-py projects." +optional = true +python-versions = ">=3.7" +files = [ + {file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"}, + {file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"}, +] + +[package.extras] +test = ["coverage", "pytest", "pytest-cov"] + [[package]] name = "urllib3" version = "1.26.20" @@ -4979,13 +5112,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -5071,35 +5204,59 @@ dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +[[package]] +name = "virtualenv" +version = "20.28.1" +description = "Virtual Python Environment builder" +optional = true +python-versions = ">=3.8" +files = [ + {file = "virtualenv-20.28.1-py3-none-any.whl", hash = "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb"}, + {file = "virtualenv-20.28.1.tar.gz", hash = "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [[package]] name = "vllm" -version = "0.6.3.post1" +version = "0.6.6.post1" description = "A high-throughput and memory-efficient inference and serving engine for LLMs" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "vllm-0.6.3.post1-cp38-abi3-manylinux1_x86_64.whl", hash = "sha256:691f10edb9869eb8b85bebfe2c0fb3c6a6b2cf2aefad7cdb2ab97688a57ca60e"}, - {file = "vllm-0.6.3.post1.tar.gz", hash = "sha256:0aae6ddd5348f86bf20e4f323c09e77d5ad2638d77f0d69323c5a63a40f8c143"}, + {file = "vllm-0.6.6.post1-cp38-abi3-manylinux1_x86_64.whl", hash = "sha256:07cd8b4bc6368b5ce37ea14936d6941021ac2ac032e2731f1de108a1e499cab4"}, + {file = "vllm-0.6.6.post1.tar.gz", hash = "sha256:d9035954a2028fd7efb2c37e137d69b568d80f193b6a8748f885676292a43a95"}, ] [package.dependencies] aiohttp = "*" -compressed-tensors = "0.6.0" +blake3 = "*" +cloudpickle = "*" +compressed-tensors = "0.8.1" +depyf = "0.18.0" einops = "*" fastapi = {version = ">=0.107.0,<0.113.dev0 || >0.114.0", markers = "python_version >= \"3.9\""} -filelock = ">=3.10.4" +filelock = ">=3.16.1" gguf = "0.10.0" -importlib-metadata = "*" -lm-format-enforcer = "0.10.6" -mistral-common = {version = ">=1.4.4", extras = ["opencv"]} +importlib_metadata = "*" +lark = "1.2.2" +lm-format-enforcer = ">=0.10.9,<0.11" +mistral_common = {version = ">=1.5.0", extras = ["opencv"]} msgspec = "*" numpy = "<2.0.0" -nvidia-ml-py = "*" -openai = ">=1.40.0" -outlines = ">=0.0.43,<0.1" +nvidia-ml-py = ">=12.560.30" +openai = ">=1.52.0" +outlines = "0.1.11" partial-json-parser = "*" pillow = "*" -prometheus-client = ">=0.18.0" +prometheus_client = ">=0.18.0" prometheus-fastapi-instrumentator = ">=7.0.0" protobuf = "*" psutil = "*" @@ -5107,115 +5264,106 @@ py-cpuinfo = "*" pydantic = ">=2.9" pyyaml = "*" pyzmq = "*" -ray = ">=2.9" +ray = {version = ">=2.9", extras = ["default"]} requests = ">=2.26.0" sentencepiece = "*" setuptools = {version = ">=74.1.1", markers = "python_version > \"3.11\""} six = {version = ">=1.16.0", markers = "python_version > \"3.11\""} tiktoken = ">=0.6.0" tokenizers = ">=0.19.1" -torch = "2.4.0" -torchvision = "0.19" +torch = "2.5.1" +torchvision = "0.20.1" tqdm = "*" transformers = ">=4.45.2" -typing-extensions = ">=4.10" +typing_extensions = ">=4.10" uvicorn = {version = "*", extras = ["standard"]} -xformers = {version = "0.0.27.post2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +xformers = {version = "0.0.28.post3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +xgrammar = {version = ">=0.1.6", markers = "platform_machine == \"x86_64\""} [package.extras] audio = ["librosa", "soundfile"] +runai = ["boto3", "runai-model-streamer", "runai-model-streamer-s3"] tensorizer = ["tensorizer (>=2.9.0)"] +video = ["decord"] [[package]] name = "watchfiles" -version = "0.24.0" +version = "1.0.3" description = "Simple, modern and high performance file watching and code reload in python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "watchfiles-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0"}, - {file = "watchfiles-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188"}, - {file = "watchfiles-0.24.0-cp310-none-win32.whl", hash = "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735"}, - {file = "watchfiles-0.24.0-cp310-none-win_amd64.whl", hash = "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec"}, - {file = "watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d"}, - {file = "watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c"}, - {file = "watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968"}, - {file = "watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444"}, - {file = "watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896"}, - {file = "watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18"}, - {file = "watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07"}, - {file = "watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22"}, - {file = "watchfiles-0.24.0-cp38-none-win32.whl", hash = "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1"}, - {file = "watchfiles-0.24.0-cp38-none-win_amd64.whl", hash = "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e"}, - {file = "watchfiles-0.24.0-cp39-none-win32.whl", hash = "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da"}, - {file = "watchfiles-0.24.0-cp39-none-win_amd64.whl", hash = "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e"}, - {file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"}, + {file = "watchfiles-1.0.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da46bb1eefb5a37a8fb6fd52ad5d14822d67c498d99bda8754222396164ae42"}, + {file = "watchfiles-1.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2b961b86cd3973f5822826017cad7f5a75795168cb645c3a6b30c349094e02e3"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34e87c7b3464d02af87f1059fedda5484e43b153ef519e4085fe1a03dd94801e"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9dd2b89a16cf7ab9c1170b5863e68de6bf83db51544875b25a5f05a7269e678"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b4691234d31686dca133c920f94e478b548a8e7c750f28dbbc2e4333e0d3da9"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90b0fe1fcea9bd6e3084b44875e179b4adcc4057a3b81402658d0eb58c98edf8"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0b90651b4cf9e158d01faa0833b073e2e37719264bcee3eac49fc3c74e7d304b"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2e9fe695ff151b42ab06501820f40d01310fbd58ba24da8923ace79cf6d702d"}, + {file = "watchfiles-1.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62691f1c0894b001c7cde1195c03b7801aaa794a837bd6eef24da87d1542838d"}, + {file = "watchfiles-1.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:275c1b0e942d335fccb6014d79267d1b9fa45b5ac0639c297f1e856f2f532552"}, + {file = "watchfiles-1.0.3-cp310-cp310-win32.whl", hash = "sha256:06ce08549e49ba69ccc36fc5659a3d0ff4e3a07d542b895b8a9013fcab46c2dc"}, + {file = "watchfiles-1.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f280b02827adc9d87f764972fbeb701cf5611f80b619c20568e1982a277d6146"}, + {file = "watchfiles-1.0.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ffe709b1d0bc2e9921257569675674cafb3a5f8af689ab9f3f2b3f88775b960f"}, + {file = "watchfiles-1.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:418c5ce332f74939ff60691e5293e27c206c8164ce2b8ce0d9abf013003fb7fe"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f492d2907263d6d0d52f897a68647195bc093dafed14508a8d6817973586b6b"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48c9f3bc90c556a854f4cab6a79c16974099ccfa3e3e150673d82d47a4bc92c9"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75d3bcfa90454dba8df12adc86b13b6d85fda97d90e708efc036c2760cc6ba44"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5691340f259b8f76b45fb31b98e594d46c36d1dc8285efa7975f7f50230c9093"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e263cc718545b7f897baeac1f00299ab6fabe3e18caaacacb0edf6d5f35513c"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c6cf7709ed3e55704cc06f6e835bf43c03bc8e3cb8ff946bf69a2e0a78d9d77"}, + {file = "watchfiles-1.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:703aa5e50e465be901e0e0f9d5739add15e696d8c26c53bc6fc00eb65d7b9469"}, + {file = "watchfiles-1.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bfcae6aecd9e0cb425f5145afee871465b98b75862e038d42fe91fd753ddd780"}, + {file = "watchfiles-1.0.3-cp311-cp311-win32.whl", hash = "sha256:6a76494d2c5311584f22416c5a87c1e2cb954ff9b5f0988027bc4ef2a8a67181"}, + {file = "watchfiles-1.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:cf745cbfad6389c0e331786e5fe9ae3f06e9d9c2ce2432378e1267954793975c"}, + {file = "watchfiles-1.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:2dcc3f60c445f8ce14156854a072ceb36b83807ed803d37fdea2a50e898635d6"}, + {file = "watchfiles-1.0.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3"}, + {file = "watchfiles-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0"}, + {file = "watchfiles-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885"}, + {file = "watchfiles-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5"}, + {file = "watchfiles-1.0.3-cp312-cp312-win32.whl", hash = "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d"}, + {file = "watchfiles-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44"}, + {file = "watchfiles-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43"}, + {file = "watchfiles-1.0.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e153a690b7255c5ced17895394b4f109d5dcc2a4f35cb809374da50f0e5c456a"}, + {file = "watchfiles-1.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac1be85fe43b4bf9a251978ce5c3bb30e1ada9784290441f5423a28633a958a7"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec98e31e1844eac860e70d9247db9d75440fc8f5f679c37d01914568d18721"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0179252846be03fa97d4d5f8233d1c620ef004855f0717712ae1c558f1974a16"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:995c374e86fa82126c03c5b4630c4e312327ecfe27761accb25b5e1d7ab50ec8"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b9cb35b7f290db1c31fb2fdf8fc6d3730cfa4bca4b49761083307f441cac5a"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f8dc09ae69af50bead60783180f656ad96bd33ffbf6e7a6fce900f6d53b08f1"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:489b80812f52a8d8c7b0d10f0d956db0efed25df2821c7a934f6143f76938bd6"}, + {file = "watchfiles-1.0.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:228e2247de583475d4cebf6b9af5dc9918abb99d1ef5ee737155bb39fb33f3c0"}, + {file = "watchfiles-1.0.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1550be1a5cb3be08a3fb84636eaafa9b7119b70c71b0bed48726fd1d5aa9b868"}, + {file = "watchfiles-1.0.3-cp313-cp313-win32.whl", hash = "sha256:16db2d7e12f94818cbf16d4c8938e4d8aaecee23826344addfaaa671a1527b07"}, + {file = "watchfiles-1.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:160eff7d1267d7b025e983ca8460e8cc67b328284967cbe29c05f3c3163711a3"}, + {file = "watchfiles-1.0.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c05b021f7b5aa333124f2a64d56e4cb9963b6efdf44e8d819152237bbd93ba15"}, + {file = "watchfiles-1.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:310505ad305e30cb6c5f55945858cdbe0eb297fc57378f29bacceb534ac34199"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddff3f8b9fa24a60527c137c852d0d9a7da2a02cf2151650029fdc97c852c974"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46e86ed457c3486080a72bc837300dd200e18d08183f12b6ca63475ab64ed651"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f79fe7993e230a12172ce7d7c7db061f046f672f2b946431c81aff8f60b2758b"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea2b51c5f38bad812da2ec0cd7eec09d25f521a8b6b6843cbccedd9a1d8a5c15"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fe4e740ea94978b2b2ab308cbf9270a246bcbb44401f77cc8740348cbaeac3d"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9af037d3df7188ae21dc1c7624501f2f90d81be6550904e07869d8d0e6766655"}, + {file = "watchfiles-1.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52bb50a4c4ca2a689fdba84ba8ecc6a4e6210f03b6af93181bb61c4ec3abaf86"}, + {file = "watchfiles-1.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c14a07bdb475eb696f85c715dbd0f037918ccbb5248290448488a0b4ef201aad"}, + {file = "watchfiles-1.0.3-cp39-cp39-win32.whl", hash = "sha256:be37f9b1f8934cd9e7eccfcb5612af9fb728fecbe16248b082b709a9d1b348bf"}, + {file = "watchfiles-1.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ef9ec8068cf23458dbf36a08e0c16f0a2df04b42a8827619646637be1769300a"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:84fac88278f42d61c519a6c75fb5296fd56710b05bbdcc74bdf85db409a03780"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c68be72b1666d93b266714f2d4092d78dc53bd11cf91ed5a3c16527587a52e29"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889a37e2acf43c377b5124166bece139b4c731b61492ab22e64d371cce0e6e80"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca05cacf2e5c4a97d02a2878a24020daca21dbb8823b023b978210a75c79098"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8af4b582d5fc1b8465d1d2483e5e7b880cc1a4e99f6ff65c23d64d070867ac58"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:127de3883bdb29dbd3b21f63126bb8fa6e773b74eaef46521025a9ce390e1073"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713f67132346bdcb4c12df185c30cf04bdf4bf6ea3acbc3ace0912cab6b7cb8c"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abd85de513eb83f5ec153a802348e7a5baa4588b818043848247e3e8986094e8"}, + {file = "watchfiles-1.0.3.tar.gz", hash = "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56"}, ] [package.dependencies] @@ -5239,344 +5387,289 @@ test = ["websockets"] [[package]] name = "websockets" -version = "13.1" +version = "14.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false +python-versions = ">=3.9" +files = [ + {file = "websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179"}, + {file = "websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434"}, + {file = "websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10"}, + {file = "websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac"}, + {file = "websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23"}, + {file = "websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e"}, + {file = "websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d"}, + {file = "websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05"}, + {file = "websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0"}, + {file = "websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b"}, + {file = "websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a"}, + {file = "websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6"}, + {file = "websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6"}, + {file = "websockets-14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc"}, + {file = "websockets-14.1-cp39-cp39-win32.whl", hash = "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4"}, + {file = "websockets-14.1-cp39-cp39-win_amd64.whl", hash = "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7"}, + {file = "websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1"}, + {file = "websockets-14.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5"}, + {file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"}, + {file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"}, +] + +[[package]] +name = "wrapt" +version = "1.17.0" +description = "Module for decorators, wrappers and monkey patching." +optional = true python-versions = ">=3.8" files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] name = "xformers" -version = "0.0.27.post2" +version = "0.0.28.post3" description = "XFormers: A collection of composable Transformer building blocks." optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "xformers-0.0.27.post2-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:7d4bd4876559fdc3cccbcaea717d3a28ca7f2fb09ab84cac3d859449ba247830"}, - {file = "xformers-0.0.27.post2-cp310-cp310-win_amd64.whl", hash = "sha256:cd476c23fea18aa7298753c031c4827a544d919ee542cec771c01bc824d0127d"}, - {file = "xformers-0.0.27.post2-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:373a1c5d65dab89ea058d17a37c07e5da5ff3b9bebf61425e26a0a5293b0d4a9"}, - {file = "xformers-0.0.27.post2-cp311-cp311-win_amd64.whl", hash = "sha256:7a26febb550b642c7da9864b6a46ccb89461571d27cfef54f7a252f03060d07c"}, - {file = "xformers-0.0.27.post2-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:3500f5ff3614aa18762fddc945e4057e7225e23f35986c6666cc49d6cb1c8ee7"}, - {file = "xformers-0.0.27.post2-cp312-cp312-win_amd64.whl", hash = "sha256:0454ba745babf43500320b1d171ef4e44dec38f279fab9df1710ca5ce44a749c"}, - {file = "xformers-0.0.27.post2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ab39ba95a7529c412c3d81e7817e2b42c31980b72e1937055fd4ba4503a34b3d"}, - {file = "xformers-0.0.27.post2-cp38-cp38-win_amd64.whl", hash = "sha256:5a83aa75a7208c359b2755af318e97e70855dbae6cdf998227f6dee220a56203"}, - {file = "xformers-0.0.27.post2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f9fca3af140a8649678e946d55e32c8be59917c4b7d0e96437c057a4bbe30e11"}, - {file = "xformers-0.0.27.post2-cp39-cp39-win_amd64.whl", hash = "sha256:d555ef6d3722941cd785cf4b7c6039b06e8a0ca1360ff661200cf043393ca5a2"}, - {file = "xformers-0.0.27.post2.tar.gz", hash = "sha256:5c3bcefabf29532cac7eb7556fb684be209698955b004aac069742e49373bdb3"}, + {file = "xformers-0.0.28.post3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:648483325366fb3c6a42246f99646101d3cfd678725b3ffc50a4708a222ae973"}, + {file = "xformers-0.0.28.post3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:825563e129f6b22885c2a91e464ff617382f4d78876cc92d96ff618e875aaee3"}, + {file = "xformers-0.0.28.post3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c550f72bb4e55b67bd847e9272b7f41d27ac82b6b99f35a710a1292f2f218a3a"}, + {file = "xformers-0.0.28.post3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e5ae1269ceea51c0d3a0a03ebe729aaae8e29dc4ca5e0f5a3bcd482045905811"}, + {file = "xformers-0.0.28.post3.tar.gz", hash = "sha256:c7a2392c874dfd8f38b73e14492baf048a4f50f77ddf522bfcf6ebf5ee84d567"}, ] [package.dependencies] numpy = "*" -torch = "2.4.0" +torch = "2.5.1" [[package]] -name = "xxhash" -version = "3.5.0" -description = "Python binding for xxHash" +name = "xgrammar" +version = "0.1.9" +description = "Efficient, Flexible and Portable Structured Generation" optional = true -python-versions = ">=3.7" +python-versions = "<4,>=3.8" files = [ - {file = "xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212"}, - {file = "xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520"}, - {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680"}, - {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da"}, - {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23"}, - {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196"}, - {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c"}, - {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482"}, - {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296"}, - {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415"}, - {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198"}, - {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442"}, - {file = "xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da"}, - {file = "xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9"}, - {file = "xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6"}, - {file = "xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1"}, - {file = "xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8"}, - {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166"}, - {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7"}, - {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623"}, - {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a"}, - {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88"}, - {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c"}, - {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2"}, - {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084"}, - {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d"}, - {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839"}, - {file = "xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da"}, - {file = "xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58"}, - {file = "xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3"}, - {file = "xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00"}, - {file = "xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9"}, - {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84"}, - {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793"}, - {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be"}, - {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6"}, - {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90"}, - {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27"}, - {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2"}, - {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d"}, - {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab"}, - {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e"}, - {file = "xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8"}, - {file = "xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e"}, - {file = "xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2"}, - {file = "xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6"}, - {file = "xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5"}, - {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc"}, - {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3"}, - {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c"}, - {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb"}, - {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f"}, - {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7"}, - {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326"}, - {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf"}, - {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7"}, - {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c"}, - {file = "xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637"}, - {file = "xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43"}, - {file = "xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b"}, - {file = "xxhash-3.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6e5f70f6dca1d3b09bccb7daf4e087075ff776e3da9ac870f86ca316736bb4aa"}, - {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e76e83efc7b443052dd1e585a76201e40b3411fe3da7af4fe434ec51b2f163b"}, - {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33eac61d0796ca0591f94548dcfe37bb193671e0c9bcf065789b5792f2eda644"}, - {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ec70a89be933ea49222fafc3999987d7899fc676f688dd12252509434636622"}, - {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86b8e7f703ec6ff4f351cfdb9f428955859537125904aa8c963604f2e9d3e7"}, - {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0adfbd36003d9f86c8c97110039f7539b379f28656a04097e7434d3eaf9aa131"}, - {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:63107013578c8a730419adc05608756c3fa640bdc6abe806c3123a49fb829f43"}, - {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:683b94dbd1ca67557850b86423318a2e323511648f9f3f7b1840408a02b9a48c"}, - {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5d2a01dcce81789cf4b12d478b5464632204f4c834dc2d064902ee27d2d1f0ee"}, - {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a9d360a792cbcce2fe7b66b8d51274ec297c53cbc423401480e53b26161a290d"}, - {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:f0b48edbebea1b7421a9c687c304f7b44d0677c46498a046079d445454504737"}, - {file = "xxhash-3.5.0-cp37-cp37m-win32.whl", hash = "sha256:7ccb800c9418e438b44b060a32adeb8393764da7441eb52aa2aa195448935306"}, - {file = "xxhash-3.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c3bc7bf8cb8806f8d1c9bf149c18708cb1c406520097d6b0a73977460ea03602"}, - {file = "xxhash-3.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:74752ecaa544657d88b1d1c94ae68031e364a4d47005a90288f3bab3da3c970f"}, - {file = "xxhash-3.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dee1316133c9b463aa81aca676bc506d3f80d8f65aeb0bba2b78d0b30c51d7bd"}, - {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:602d339548d35a8579c6b013339fb34aee2df9b4e105f985443d2860e4d7ffaa"}, - {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:695735deeddfb35da1677dbc16a083445360e37ff46d8ac5c6fcd64917ff9ade"}, - {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1030a39ba01b0c519b1a82f80e8802630d16ab95dc3f2b2386a0b5c8ed5cbb10"}, - {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5bc08f33c4966f4eb6590d6ff3ceae76151ad744576b5fc6c4ba8edd459fdec"}, - {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160e0c19ee500482ddfb5d5570a0415f565d8ae2b3fd69c5dcfce8a58107b1c3"}, - {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f1abffa122452481a61c3551ab3c89d72238e279e517705b8b03847b1d93d738"}, - {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d5e9db7ef3ecbfc0b4733579cea45713a76852b002cf605420b12ef3ef1ec148"}, - {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:23241ff6423378a731d84864bf923a41649dc67b144debd1077f02e6249a0d54"}, - {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:82b833d5563fefd6fceafb1aed2f3f3ebe19f84760fdd289f8b926731c2e6e91"}, - {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a80ad0ffd78bef9509eee27b4a29e56f5414b87fb01a888353e3d5bda7038bd"}, - {file = "xxhash-3.5.0-cp38-cp38-win32.whl", hash = "sha256:50ac2184ffb1b999e11e27c7e3e70cc1139047e7ebc1aa95ed12f4269abe98d4"}, - {file = "xxhash-3.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:392f52ebbb932db566973693de48f15ce787cabd15cf6334e855ed22ea0be5b3"}, - {file = "xxhash-3.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301"}, - {file = "xxhash-3.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab"}, - {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f"}, - {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd"}, - {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc"}, - {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754"}, - {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6"}, - {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898"}, - {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833"}, - {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6"}, - {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af"}, - {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606"}, - {file = "xxhash-3.5.0-cp39-cp39-win32.whl", hash = "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4"}, - {file = "xxhash-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558"}, - {file = "xxhash-3.5.0-cp39-cp39-win_arm64.whl", hash = "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e"}, - {file = "xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c"}, - {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986"}, - {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6"}, - {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b"}, - {file = "xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da"}, - {file = "xxhash-3.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b4154c00eb22e4d543f472cfca430e7962a0f1d0f3778334f2e08a7ba59363c"}, - {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d30bbc1644f726b825b3278764240f449d75f1a8bdda892e641d4a688b1494ae"}, - {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa0b72f2423e2aa53077e54a61c28e181d23effeaafd73fcb9c494e60930c8e"}, - {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13de2b76c1835399b2e419a296d5b38dc4855385d9e96916299170085ef72f57"}, - {file = "xxhash-3.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0691bfcc4f9c656bcb96cc5db94b4d75980b9d5589f2e59de790091028580837"}, - {file = "xxhash-3.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:297595fe6138d4da2c8ce9e72a04d73e58725bb60f3a19048bc96ab2ff31c692"}, - {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1276d369452040cbb943300dc8abeedab14245ea44056a2943183822513a18"}, - {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2061188a1ba352fc699c82bff722f4baacb4b4b8b2f0c745d2001e56d0dfb514"}, - {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c384c434021e4f62b8d9ba0bc9467e14d394893077e2c66d826243025e1f81"}, - {file = "xxhash-3.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e6a4dd644d72ab316b580a1c120b375890e4c52ec392d4aef3c63361ec4d77d1"}, - {file = "xxhash-3.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9"}, - {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1"}, - {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f"}, - {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0"}, - {file = "xxhash-3.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240"}, - {file = "xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f"}, + {file = "xgrammar-0.1.9-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d8dd6955267b53604a8888db56166e1a1a62dc30082fb09ae97d0a680fd46527"}, + {file = "xgrammar-0.1.9-cp310-cp310-win_amd64.whl", hash = "sha256:938493a26204d8d7900cd3805cea97c5a4e08c3b3c9b7bea5e53820280b41af8"}, + {file = "xgrammar-0.1.9-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:344f02ed0f550d7fcb3ea837f8369faf357c44051974c86b7363517412829700"}, + {file = "xgrammar-0.1.9-cp311-cp311-win_amd64.whl", hash = "sha256:63893935796af60bdb5afd2b656baddbaf5dfa9d42a71fe347eda33b4584cb51"}, + {file = "xgrammar-0.1.9-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:473a6dc30cba150faa2f1102f576deace98342a293ceb2757a7d5ddd240f6260"}, + {file = "xgrammar-0.1.9-cp312-cp312-win_amd64.whl", hash = "sha256:d3ba9ec2c18fbb94bdee36e66e026770e8f47398127b0192b36b9c80b6d2b868"}, + {file = "xgrammar-0.1.9-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e99200b16462d71850b41cf77b5dff0157e1c7615737d20ddc6b1e001085f2a"}, + {file = "xgrammar-0.1.9-cp39-cp39-win_amd64.whl", hash = "sha256:c1a7fd1bce1edd6e2727ab426e11878b0f9ff117dae8c02ea03835c5138d943a"}, ] +[package.dependencies] +pybind11 = "*" +pydantic = "*" +pytest = "*" +sentencepiece = "*" +tiktoken = "*" +torch = "*" +transformers = "*" + [[package]] name = "yarl" -version = "1.16.0" +version = "1.18.3" description = "Yet another URL library" optional = true python-versions = ">=3.9" files = [ - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32468f41242d72b87ab793a86d92f885355bcf35b3355aa650bfa846a5c60058"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:234f3a3032b505b90e65b5bc6652c2329ea7ea8855d8de61e1642b74b4ee65d2"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a0296040e5cddf074c7f5af4a60f3fc42c0237440df7bcf5183be5f6c802ed5"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6c14dd7c7c0badba48157474ea1f03ebee991530ba742d381b28d4f314d6f3"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b140e532fe0266003c936d017c1ac301e72ee4a3fd51784574c05f53718a55d8"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:019f5d58093402aa8f6661e60fd82a28746ad6d156f6c5336a70a39bd7b162b9"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c42998fd1cbeb53cd985bff0e4bc25fbe55fd6eb3a545a724c1012d69d5ec84"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7c30fb38c300fe8140df30a046a01769105e4cf4282567a29b5cdb635b66c4"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e49e0fd86c295e743fd5be69b8b0712f70a686bc79a16e5268386c2defacaade"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b9ca7b9147eb1365c8bab03c003baa1300599575effad765e0b07dd3501ea9af"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27e11db3f1e6a51081a981509f75617b09810529de508a181319193d320bc5c7"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8994c42f4ca25df5380ddf59f315c518c81df6a68fed5bb0c159c6cb6b92f120"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:542fa8e09a581bcdcbb30607c7224beff3fdfb598c798ccd28a8184ffc18b7eb"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2bd6a51010c7284d191b79d3b56e51a87d8e1c03b0902362945f15c3d50ed46b"}, - {file = "yarl-1.16.0-cp310-cp310-win32.whl", hash = "sha256:178ccb856e265174a79f59721031060f885aca428983e75c06f78aa24b91d929"}, - {file = "yarl-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe8bba2545427418efc1929c5c42852bdb4143eb8d0a46b09de88d1fe99258e7"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d8643975a0080f361639787415a038bfc32d29208a4bf6b783ab3075a20b1ef3"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:676d96bafc8c2d0039cea0cd3fd44cee7aa88b8185551a2bb93354668e8315c2"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9525f03269e64310416dbe6c68d3b23e5d34aaa8f47193a1c45ac568cecbc49"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b37d5ec034e668b22cf0ce1074d6c21fd2a08b90d11b1b73139b750a8b0dd97"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f32c4cb7386b41936894685f6e093c8dfaf0960124d91fe0ec29fe439e201d0"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b8e265a0545637492a7e12fd7038370d66c9375a61d88c5567d0e044ded9202"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:789a3423f28a5fff46fbd04e339863c169ece97c827b44de16e1a7a42bc915d2"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1d1f45e3e8d37c804dca99ab3cf4ab3ed2e7a62cd82542924b14c0a4f46d243"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:621280719c4c5dad4c1391160a9b88925bb8b0ff6a7d5af3224643024871675f"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed097b26f18a1f5ff05f661dc36528c5f6735ba4ce8c9645e83b064665131349"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2f1fe2b2e3ee418862f5ebc0c0083c97f6f6625781382f828f6d4e9b614eba9b"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:87dd10bc0618991c66cee0cc65fa74a45f4ecb13bceec3c62d78ad2e42b27a16"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4199db024b58a8abb2cfcedac7b1292c3ad421684571aeb622a02f242280e8d6"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:99a9dcd4b71dd5f5f949737ab3f356cfc058c709b4f49833aeffedc2652dac56"}, - {file = "yarl-1.16.0-cp311-cp311-win32.whl", hash = "sha256:a9394c65ae0ed95679717d391c862dece9afacd8fa311683fc8b4362ce8a410c"}, - {file = "yarl-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b9101f528ae0f8f65ac9d64dda2bb0627de8a50344b2f582779f32fda747c1d"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4ffb7c129707dd76ced0a4a4128ff452cecf0b0e929f2668ea05a371d9e5c104"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1a5e9d8ce1185723419c487758d81ac2bde693711947032cce600ca7c9cda7d6"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d743e3118b2640cef7768ea955378c3536482d95550222f908f392167fe62059"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26768342f256e6e3c37533bf9433f5f15f3e59e3c14b2409098291b3efaceacb"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1b0796168b953bca6600c5f97f5ed407479889a36ad7d17183366260f29a6b9"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858728086914f3a407aa7979cab743bbda1fe2bdf39ffcd991469a370dd7414d"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5570e6d47bcb03215baf4c9ad7bf7c013e56285d9d35013541f9ac2b372593e7"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66ea8311422a7ba1fc79b4c42c2baa10566469fe5a78500d4e7754d6e6db8724"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:649bddcedee692ee8a9b7b6e38582cb4062dc4253de9711568e5620d8707c2a3"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a91654adb7643cb21b46f04244c5a315a440dcad63213033826549fa2435f71"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b439cae82034ade094526a8f692b9a2b5ee936452de5e4c5f0f6c48df23f8604"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:571f781ae8ac463ce30bacebfaef2c6581543776d5970b2372fbe31d7bf31a07"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa7943f04f36d6cafc0cf53ea89824ac2c37acbdb4b316a654176ab8ffd0f968"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3"}, - {file = "yarl-1.16.0-cp312-cp312-win32.whl", hash = "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67"}, - {file = "yarl-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36"}, - {file = "yarl-1.16.0-cp313-cp313-win32.whl", hash = "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b"}, - {file = "yarl-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab2b2ac232110a1fdb0d3ffcd087783edd3d4a6ced432a1bf75caf7b7be70916"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f8713717a09acbfee7c47bfc5777e685539fefdd34fa72faf504c8be2f3df4e"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdcffe1dbcb4477d2b4202f63cd972d5baa155ff5a3d9e35801c46a415b7f71a"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a91217208306d82357c67daeef5162a41a28c8352dab7e16daa82e3718852a7"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ab3ed42c78275477ea8e917491365e9a9b69bb615cb46169020bd0aa5e2d6d3"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:707ae579ccb3262dfaef093e202b4c3fb23c3810e8df544b1111bd2401fd7b09"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7a852d1cd0b8d8b37fc9d7f8581152add917a98cfe2ea6e241878795f917ae"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3f1cc3d3d4dc574bebc9b387f6875e228ace5748a7c24f49d8f01ac1bc6c31b"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5ff96da263740779b0893d02b718293cc03400c3a208fc8d8cd79d9b0993e532"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3d375a19ba2bfe320b6d873f3fb165313b002cef8b7cc0a368ad8b8a57453837"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:62c7da0ad93a07da048b500514ca47b759459ec41924143e2ddb5d7e20fd3db5"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:147b0fcd0ee33b4b5f6edfea80452d80e419e51b9a3f7a96ce98eaee145c1581"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:504e1fe1cc4f170195320eb033d2b0ccf5c6114ce5bf2f617535c01699479bca"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bdcf667a5dec12a48f669e485d70c54189f0639c2157b538a4cffd24a853624f"}, - {file = "yarl-1.16.0-cp39-cp39-win32.whl", hash = "sha256:e9951afe6557c75a71045148890052cb942689ee4c9ec29f5436240e1fcc73b7"}, - {file = "yarl-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d7aaa8ff95d0840e289423e7dc35696c2b058d635f945bf05b5cd633146b027"}, - {file = "yarl-1.16.0-py3-none-any.whl", hash = "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3"}, - {file = "yarl-1.16.0.tar.gz", hash = "sha256:b6f687ced5510a9a2474bbae96a4352e5ace5fa34dc44a217b0537fec1db00b4"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] @@ -5586,13 +5679,13 @@ propcache = ">=0.2.0" [[package]] name = "zipp" -version = "3.20.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -5609,4 +5702,4 @@ vllm = ["vllm"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "2fc504f3facbfbd64b2442d18a7f7913517c6e5da64083f8083a0af3f9059d9f" +content-hash = "062fed835afbef1890ec78bc4b97b4f4937b0030f03acdbe6b5339719879fec6" diff --git a/python/huggingfaceserver/pyproject.toml b/python/huggingfaceserver/pyproject.toml index 919d47f11fb..4a34f355d48 100644 --- a/python/huggingfaceserver/pyproject.toml +++ b/python/huggingfaceserver/pyproject.toml @@ -1,27 +1,23 @@ [tool.poetry] name = "huggingfaceserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for huggingface. Not intended for use outside KServe Frameworks Images." authors = ["Dan Sun "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" readme = "README.md" -packages = [ - { include = "huggingfaceserver" }, -] +packages = [{ include = "huggingfaceserver" }] [tool.poetry.dependencies] python = ">=3.9,<3.13" kserve = { path = "../kserve", extras = ["storage"], develop = true } transformers = ">=4.45.0" accelerate = "~0.32.0" -torch = "~2.4.0" -vllm = { version = "^0.6.3.post1", optional = true } -setuptools = {version = ">=70.0.0", python = "3.12"} # setuptools is not part of python 3.12 +torch = "~2.5.0" +vllm = { version = "^0.6.6.post1", optional = true } +setuptools = { version = ">=70.0.0" } [tool.poetry.extras] -vllm = [ - "vllm", -] +vllm = ["vllm"] [tool.poetry.group.test] optional = true diff --git a/python/huggingfaceserver/test_health_check.py b/python/huggingfaceserver/test_health_check.py index b3542159861..38bac68c2de 100644 --- a/python/huggingfaceserver/test_health_check.py +++ b/python/huggingfaceserver/test_health_check.py @@ -15,29 +15,16 @@ import unittest import requests from unittest.mock import patch, MagicMock -import health_check +import health_check as health_check class TestHealthCheck(unittest.TestCase): - @patch("health_check.ray.init") def test_initialize_ray_cluster(self, mock_ray_init): mock_ray_init.return_value = MagicMock() - result = health_check.initialize_ray_cluster() - # mock_ray_init.assert_called_once_with(address="auto") - self.assertEqual(result, "Ray initialized") - - @patch("health_check.ray.init") - def test_perform_health_check_success(self, mock_ray_init): - mock_ray_init.return_value = MagicMock() - result = health_check.check_startup() - self.assertEqual(result, "Healthy") - - @patch("health_check.ray.init") - def test_perform_health_check_failure(self, mock_ray_init): - mock_ray_init.side_effect = Exception("Ray init failed") - result = health_check.check_startup() - self.assertEqual(result, "Unhealthy") + result = health_check.initialize_ray_cluster("auto") + mock_ray_init.assert_called_once_with(address="auto") + self.assertEqual(result, None) # Test check_gpu_usage with healthy GPU usage @patch("health_check.ray.init") @@ -60,7 +47,7 @@ def test_check_gpu_usage_healthy(mock_ray_init, mock_ray_nodes, capsys): }, }, ] - status = health_check.check_gpu_usage("Test GPU Usage") + status = health_check.check_gpu_usage("auto") assert status == "Healthy" # Test check_gpu_usage with unhealthy GPU usage @@ -84,7 +71,7 @@ def test_check_gpu_usage_ungihealthy(mock_ray_init, mock_ray_nodes, capsys): }, }, ] - status = health_check.check_gpu_usage("Test GPU Usage") + status = health_check.check_gpu_usage("auto") assert status == "Unhealthy" # Test check_registered_nodes with correct number of nodes @@ -102,7 +89,7 @@ def test_check_registered_nodes_healthy(mock_ray_init, mock_ray_nodes, capsys): "Alive": True, }, ] - status = health_check.check_registered_nodes(2) + status = health_check.check_registered_nodes(2, "auto") assert status == "Healthy" # Test check_registered_nodes with incorrect number of nodes @@ -116,35 +103,47 @@ def test_check_registered_nodes_unhealthy(mock_ray_init, mock_ray_nodes, capsys) "Alive": True, } ] - status = health_check.check_registered_nodes(2) + status = health_check.check_registered_nodes(2, "auto") assert status == "Unhealthy" @patch("health_check.requests.get") - def test_check_runtime_health_healthy(self, mock_get): + def test_check_runtime_health_healthy_without_retries(self, mock_get): mock_get.return_value.status_code = 200 health_check_url = "http://example.com/health" - status = health_check.check_runtime_health(health_check_url) - + status = health_check.check_runtime_health(health_check_url, retries=0) assert status == "Healthy" mock_get.assert_called_once_with(health_check_url, timeout=5) @patch("health_check.requests.get") - def test_check_runtime_health_unhealthy_status_code(self, mock_get): - mock_get.return_value.status_code = 500 + def test_check_runtime_health_healthy_with_retries(self, mock_get): + mock_get.side_effect = [ + MagicMock(status_code=500), # First call + MagicMock(status_code=200), # Second call + ] health_check_url = "http://example.com/health" - status = health_check.check_runtime_health(health_check_url) + status = health_check.check_runtime_health(health_check_url, retries=1) + assert status == "Healthy" + @patch("health_check.requests.get") + def test_check_runtime_health_unhealthy_status_code_with_retries(self, mock_get): + mock_get.side_effect = [ + MagicMock(status_code=500), # First call + MagicMock(status_code=500), # Second call + ] + health_check_url = "http://example.com/health" + status = health_check.check_runtime_health(health_check_url, retries=1) assert status == "Unhealthy" - mock_get.assert_called_once_with(health_check_url, timeout=5) @patch("health_check.requests.get") - def test_check_runtime_health_request_exception(self, mock_get): - mock_get.side_effect = requests.RequestException + def test_check_runtime_health_request_exception_with_retries(self, mock_get): + mock_get.side_effect = [ + requests.ConnectionError(), + requests.ConnectionError(), + ] + # mock_get.side_effect = requests.RequestException health_check_url = "http://example.com/health" - status = health_check.check_runtime_health(health_check_url) - + status = health_check.check_runtime_health(health_check_url, retries=1) assert status == "Unhealthy" - mock_get.assert_called_once_with(health_check_url, timeout=5) if __name__ == "__main__": diff --git a/python/huggingfaceserver/tests/test_vllm_model.py b/python/huggingfaceserver/tests/test_vllm_model.py index a543556c3b7..9926287d38e 100644 --- a/python/huggingfaceserver/tests/test_vllm_model.py +++ b/python/huggingfaceserver/tests/test_vllm_model.py @@ -77,6 +77,7 @@ async def mock_get_model_config(): seed=0, dtype=dtype, max_model_len=max_model_len, + task="auto", ) mock_vllm_engine = mock.AsyncMock(spec=AsyncLLMEngine) diff --git a/python/kserve/docs/V1beta1CustomExplainer.md b/python/kserve/docs/V1beta1CustomExplainer.md index f31a63b7aa5..fc9c41c7ebb 100644 --- a/python/kserve/docs/V1beta1CustomExplainer.md +++ b/python/kserve/docs/V1beta1CustomExplainer.md @@ -20,7 +20,7 @@ Name | Type | Description | Notes **hostname** | **str** | Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. | [optional] **image_pull_secrets** | [**list[V1LocalObjectReference]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1LocalObjectReference.md) | ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod | [optional] **init_containers** | [**list[V1Container]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Container.md) | List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | [optional] -**node_name** | **str** | NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. | [optional] +**node_name** | **str** | NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename | [optional] **node_selector** | **dict(str, str)** | NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ | [optional] **os** | [**V1PodOS**](V1PodOS.md) | | [optional] **overhead** | [**dict(str, ResourceQuantity)**](ResourceQuantity.md) | Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md | [optional] diff --git a/python/kserve/docs/V1beta1CustomPredictor.md b/python/kserve/docs/V1beta1CustomPredictor.md index 551cf7ce1fa..6aac12d3751 100644 --- a/python/kserve/docs/V1beta1CustomPredictor.md +++ b/python/kserve/docs/V1beta1CustomPredictor.md @@ -20,7 +20,7 @@ Name | Type | Description | Notes **hostname** | **str** | Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. | [optional] **image_pull_secrets** | [**list[V1LocalObjectReference]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1LocalObjectReference.md) | ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod | [optional] **init_containers** | [**list[V1Container]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Container.md) | List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | [optional] -**node_name** | **str** | NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. | [optional] +**node_name** | **str** | NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename | [optional] **node_selector** | **dict(str, str)** | NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ | [optional] **os** | [**V1PodOS**](V1PodOS.md) | | [optional] **overhead** | [**dict(str, ResourceQuantity)**](ResourceQuantity.md) | Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md | [optional] diff --git a/python/kserve/docs/V1beta1CustomTransformer.md b/python/kserve/docs/V1beta1CustomTransformer.md index 4f9fca7a764..aec8cbabff0 100644 --- a/python/kserve/docs/V1beta1CustomTransformer.md +++ b/python/kserve/docs/V1beta1CustomTransformer.md @@ -20,7 +20,7 @@ Name | Type | Description | Notes **hostname** | **str** | Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. | [optional] **image_pull_secrets** | [**list[V1LocalObjectReference]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1LocalObjectReference.md) | ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod | [optional] **init_containers** | [**list[V1Container]**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Container.md) | List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | [optional] -**node_name** | **str** | NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. | [optional] +**node_name** | **str** | NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename | [optional] **node_selector** | **dict(str, str)** | NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ | [optional] **os** | [**V1PodOS**](V1PodOS.md) | | [optional] **overhead** | [**dict(str, ResourceQuantity)**](ResourceQuantity.md) | Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md | [optional] diff --git a/python/kserve/docs/V1beta1InferenceServicesConfig.md b/python/kserve/docs/V1beta1InferenceServicesConfig.md index 3901fa327d1..c417c76f06d 100644 --- a/python/kserve/docs/V1beta1InferenceServicesConfig.md +++ b/python/kserve/docs/V1beta1InferenceServicesConfig.md @@ -4,6 +4,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **explainers** | [**V1beta1ExplainersConfig**](V1beta1ExplainersConfig.md) | | +**resource** | [**V1beta1ResourceConfig**](V1beta1ResourceConfig.md) | | [optional] +**service_annotation_disallowed_list** | **list[str]** | ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative revisions | [optional] +**service_label_disallowed_list** | **list[str]** | ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/python/kserve/docs/V1beta1IngressConfig.md b/python/kserve/docs/V1beta1IngressConfig.md index c54e90e7547..ff864d6b572 100644 --- a/python/kserve/docs/V1beta1IngressConfig.md +++ b/python/kserve/docs/V1beta1IngressConfig.md @@ -7,10 +7,12 @@ Name | Type | Description | Notes **disable_ingress_creation** | **bool** | | [optional] **disable_istio_virtual_host** | **bool** | | [optional] **domain_template** | **str** | | [optional] +**enable_gateway_api** | **bool** | | [optional] **ingress_class_name** | **str** | | [optional] **ingress_domain** | **str** | | [optional] **ingress_gateway** | **str** | | [optional] **knative_local_gateway_service** | **str** | | [optional] +**kserve_ingress_gateway** | **str** | | [optional] **local_gateway** | **str** | | [optional] **local_gateway_service** | **str** | | [optional] **path_template** | **str** | | [optional] diff --git a/python/kserve/docs/V1beta1LocalModelConfig.md b/python/kserve/docs/V1beta1LocalModelConfig.md index bc3df9c3d39..254e1a07efc 100644 --- a/python/kserve/docs/V1beta1LocalModelConfig.md +++ b/python/kserve/docs/V1beta1LocalModelConfig.md @@ -4,6 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **default_job_image** | **str** | | [optional] +**disable_volume_management** | **bool** | | [optional] **enabled** | **bool** | | [default to False] **fs_group** | **int** | | [optional] **job_namespace** | **str** | | [default to ''] diff --git a/python/kserve/docs/V1beta1ResourceConfig.md b/python/kserve/docs/V1beta1ResourceConfig.md new file mode 100644 index 00000000000..c4582371c67 --- /dev/null +++ b/python/kserve/docs/V1beta1ResourceConfig.md @@ -0,0 +1,13 @@ +# V1beta1ResourceConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**cpu_limit** | **str** | | [optional] +**cpu_request** | **str** | | [optional] +**memory_limit** | **str** | | [optional] +**memory_request** | **str** | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/python/kserve/kserve/api/kserve_client.py b/python/kserve/kserve/api/kserve_client.py index a36a17e3c3a..5f2a2620dfd 100644 --- a/python/kserve/kserve/api/kserve_client.py +++ b/python/kserve/kserve/api/kserve_client.py @@ -13,11 +13,14 @@ # limitations under the License. import time +from typing import List from urllib.parse import urlparse import requests from kubernetes import client, config +from ..models.v1alpha1_local_model_cache import V1alpha1LocalModelCache +from ..models.v1alpha1_local_model_node_group import V1alpha1LocalModelNodeGroup from .creds_utils import set_gcs_credentials, set_s3_credentials, set_azure_credentials from .watch import isvc_watch from ..constants import constants @@ -141,7 +144,7 @@ def create( constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, inferenceservice, ) except client.rest.ApiException as e: @@ -192,7 +195,7 @@ def get( constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, name, ) except client.rest.ApiException as e: @@ -210,7 +213,7 @@ def get( constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, ) except client.rest.ApiException as e: raise RuntimeError( @@ -241,7 +244,7 @@ def patch( constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, name, inferenceservice, ) @@ -291,7 +294,7 @@ def replace( constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, name, inferenceservice, ) @@ -328,7 +331,7 @@ def delete(self, name, namespace=None, version=constants.KSERVE_V1BETA1_VERSION) constants.KSERVE_GROUP, version, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, name, ) except client.rest.ApiException as e: @@ -646,3 +649,186 @@ def wait_ig_ready( name, current_ig ) ) + + def create_local_model_node_group( + self, localmodelnodegroup: V1alpha1LocalModelNodeGroup + ): + """ + Create a local model node group + + :param localmodelnodegroup: local model node group object + :return: created local model node group object + """ + version = localmodelnodegroup.api_version.split("/")[1] + + try: + output = self.api_instance.create_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELNODEGROUP, + localmodelnodegroup, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->create_cluster_custom_object:{e}%s\n" + ) from e + return output + + def get_local_model_node_group( + self, name: str, version: str = constants.KSERVE_V1ALPHA1_VERSION + ) -> object: + """ + Get the local model node group + + :param name: existing local model node group name + :param version: api group version. Default to v1alpha + :return: local model node group object + """ + try: + return self.api_instance.get_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELNODEGROUP, + name, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->get_cluster_custom_object:{e}%s\n" + ) from e + + def delete_local_model_node_group( + self, name: str, version: str = constants.KSERVE_V1ALPHA1_VERSION + ): + """ + Delete the local model node group + + :param name: local model node group name + :param version: api group version. Default to v1alpha + """ + try: + self.api_instance.delete_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELNODEGROUP, + name, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->delete_cluster_custom_object:{e}%s\n" + ) from e + + def create_local_model_cache( + self, localmodelcache: V1alpha1LocalModelCache + ) -> object: + """ + Create a local model cache + + :param localmodelcache: local model cache object + :return: created local model cache object + """ + version = localmodelcache.api_version.split("/")[1] + + try: + output = self.api_instance.create_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELCACHE, + localmodelcache, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->create_cluster_custom_object:{e}%s\n" + ) from e + return output + + def get_local_model_cache( + self, name: str, version: str = constants.KSERVE_V1ALPHA1_VERSION + ) -> object: + """ + Get the local model cache + + :param name: existing local model cache name + :param version: api group version. Default to v1alpha1 + :return: local model cache object + """ + try: + return self.api_instance.get_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELCACHE, + name, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->get_cluster_custom_object:{e}%s\n" + ) from e + + def delete_local_model_cache( + self, name: str, version: str = constants.KSERVE_V1ALPHA1_VERSION + ): + """ + Delete the local model cache + + :param name: local model cache name + :param version: api group version. Default to v1alpha1 + """ + try: + self.api_instance.delete_cluster_custom_object( + constants.KSERVE_GROUP, + version, + constants.KSERVE_PLURAL_LOCALMODELCACHE, + name, + ) + except client.rest.ApiException as e: + raise RuntimeError( + f"Exception when calling CustomObjectsApi->delete_cluster_custom_object:{e}%s\n" + ) from e + + def is_local_model_cache_ready( + self, + name: str, + nodes: List[str], + version: str = constants.KSERVE_V1ALPHA1_VERSION, + ) -> bool: + """ + Verify if the model is successfully cached on the specified node. + + :param name: local model cache name + :param node_name: name of the node to check if the model is cached + :param version: api group version + :return: true if the model is successfully cached, else false. + """ + local_model_cache = self.get_local_model_cache(name, version=version) + node_status = local_model_cache.get("status", {}).get("nodeStatus", {}) + for node in nodes: + if node_status.get(node, "") != "NodeDownloaded": + return False + return True + + def wait_local_model_cache_ready( + self, + name: str, + nodes: List[str], + version: str = constants.KSERVE_V1ALPHA1_VERSION, + timeout_seconds: int = 600, + polling_interval: int = 10, + ): + """ + Wait for model to be cached locally for specified nodes until timeout. + + :param name: local model cache name + :param nodes: list of node names to check if the model is cached + :param version: api group version + :param timeout_seconds: timeout seconds for waiting, default to 600s. + :param polling_interval: The time interval to poll status + :return: + """ + for _ in range(round(timeout_seconds / polling_interval)): + time.sleep(polling_interval) + if self.is_local_model_cache_ready(name, nodes, version=version): + return + + current_local_model_cache = self.get_local_model_cache(name, version=version) + raise RuntimeError( + f"Timeout while caching the model. The current state of LocalModelCache is: {current_local_model_cache}" + ) diff --git a/python/kserve/kserve/api/watch.py b/python/kserve/kserve/api/watch.py index 6af64e8360b..c73c513dfb5 100644 --- a/python/kserve/kserve/api/watch.py +++ b/python/kserve/kserve/api/watch.py @@ -36,7 +36,7 @@ def isvc_watch(name=None, namespace=None, timeout_seconds=600, generation=0): constants.KSERVE_GROUP, constants.KSERVE_V1BETA1_VERSION, namespace, - constants.KSERVE_PLURAL, + constants.KSERVE_PLURAL_INFERENCESERVICE, timeout_seconds=timeout_seconds, ) diff --git a/python/kserve/kserve/constants/constants.py b/python/kserve/kserve/constants/constants.py index 93c0df857ad..b4ebd77a86e 100644 --- a/python/kserve/kserve/constants/constants.py +++ b/python/kserve/kserve/constants/constants.py @@ -17,12 +17,18 @@ # KServe K8S constants KSERVE_GROUP = "serving.kserve.io" -KSERVE_KIND = "InferenceService" -KSERVE_PLURAL = "inferenceservices" +KSERVE_KIND_INFERENCESERVICE = "InferenceService" +KSERVE_PLURAL_INFERENCESERVICE = "inferenceservices" KSERVE_KIND_TRAINEDMODEL = "TrainedModel" KSERVE_PLURAL_TRAINEDMODEL = "trainedmodels" KSERVE_KIND_INFERENCEGRAPH = "InferenceGraph" KSERVE_PLURAL_INFERENCEGRAPH = "inferencegraphs" +KSERVE_KIND_LOCALMODELNODEGROUP = "LocalModelNodeGroup" +KSERVE_PLURAL_LOCALMODELNODEGROUP = "localmodelnodegroups" +KSERVE_KIND_LOCALMODELCACHE = "LocalModelCache" +KSERVE_PLURAL_LOCALMODELCACHE = "localmodelcaches" +KSERVE_KIND_LOCALMODELNODE = "LocalModelNode" +KSERVE_PLURAL_LOCALMODELNODE = "localmodelnodes" KSERVE_V1BETA1_VERSION = "v1beta1" KSERVE_V1ALPHA1_VERSION = "v1alpha1" diff --git a/python/kserve/kserve/inference_client.py b/python/kserve/kserve/inference_client.py index e2378cc965d..3d9b6d06a6d 100644 --- a/python/kserve/kserve/inference_client.py +++ b/python/kserve/kserve/inference_client.py @@ -426,7 +426,7 @@ def _construct_url( relative_url = "/" + relative_url return base_url.join(base_url.path + relative_url) - def _consturct_http_status_error( + def _construct_http_status_error( self, response: httpx.Response ) -> httpx.HTTPStatusError: message = ( @@ -506,7 +506,7 @@ async def infer( "response code: %s, content: %s", response.status_code, response.text ) if not response.is_success: - raise self._consturct_http_status_error(response) + raise self._construct_http_status_error(response) if response_headers is not None: response_headers.update(response.headers) # If inference graph result, return it as dict @@ -561,7 +561,7 @@ async def explain( "response code: %s, content: %s", response.status_code, response.text ) if not response.is_success: - raise self._consturct_http_status_error(response) + raise self._construct_http_status_error(response) return orjson.loads(response.content) async def is_server_ready( @@ -593,7 +593,7 @@ async def is_server_ready( "response code: %s, content: %s", response.status_code, response.text ) if not response.is_success: - raise self._consturct_http_status_error(response) + raise self._construct_http_status_error(response) return response.json().get("ready") async def is_server_live( @@ -627,7 +627,7 @@ async def is_server_live( "response code: %s, content: %s", response.status_code, response.text ) if not response.is_success: - raise self._consturct_http_status_error(response) + raise self._construct_http_status_error(response) if is_v1(self._config.protocol): is_live = response.json().get("status").lower() == "alive" elif is_v2(self._config.protocol): @@ -678,7 +678,7 @@ async def is_model_ready( return False # Raise for other status codes if not response.is_success: - raise self._consturct_http_status_error(response) + raise self._construct_http_status_error(response) return response.json().get("ready") async def close(self): diff --git a/python/kserve/kserve/model_server.py b/python/kserve/kserve/model_server.py index 9265e14c46e..e2a325ebd52 100644 --- a/python/kserve/kserve/model_server.py +++ b/python/kserve/kserve/model_server.py @@ -36,7 +36,7 @@ from .protocol.dataplane import DataPlane from .protocol.grpc.server import GRPCServer from .protocol.model_repository_extension import ModelRepositoryExtension -from .protocol.rest.server import UvicornServer +from .protocol.rest.server import RESTServer from .utils import utils from .utils.inference_client_factory import InferenceClientFactory @@ -237,15 +237,6 @@ def __init__( self.model_repository_extension = ModelRepositoryExtension( model_registry=self.registered_models ) - self._grpc_server = None - self._rest_server = None - if self.enable_grpc: - self._grpc_server = GRPCServer( - grpc_port, - self.dataplane, - self.model_repository_extension, - kwargs=vars(args), - ) if args.configure_logging: # If the logger does not have any handlers, then the logger is not configured. # For backward compatibility, we configure the logger here. @@ -264,86 +255,77 @@ def __init__( self.dataplane = DataPlane( model_registry=self.registered_models, predictor_config=predictor_config ) - - async def _serve_rest(self): - logger.info(f"Starting uvicorn with {self.workers} workers") - loop = asyncio.get_event_loop() - if sys.platform not in ["win32", "win64"]: - sig_list = [signal.SIGINT, signal.SIGTERM, signal.SIGQUIT] - else: - sig_list = [signal.SIGINT, signal.SIGTERM] - - for sig in sig_list: - loop.add_signal_handler( - sig, lambda s=sig: asyncio.create_task(self.stop(sig=s)) - ) - if self._custom_exception_handler is None: - loop.set_exception_handler(self.default_exception_handler) - else: - loop.set_exception_handler(self._custom_exception_handler) - self._rest_server = UvicornServer( + self._rest_server = self._rest_server = RESTServer( app, - self.http_port, self.dataplane, self.model_repository_extension, + self.http_port, # By setting log_config to None we tell Uvicorn not to configure logging as it is already # configured by kserve. log_config=None, access_log_format=self.access_log_format, workers=self.workers, ) - await self._rest_server.run() - - def start(self, models: List[BaseKServeModel]) -> None: - """Start the model server with a set of registered models. + self._grpc_server = None + if self.enable_grpc: + self._grpc_server = GRPCServer( + grpc_port, + self.dataplane, + self.model_repository_extension, + kwargs=vars(args), + ) - Args: - models: a list of models to register to the model server. - """ - if isinstance(models, list): - at_least_one_model_ready = False - for model in models: - if isinstance(model, BaseKServeModel): - if model.ready: - at_least_one_model_ready = True - self.register_model(model) - # pass whether to log request latency into the model - model.enable_latency_logging = self.enable_latency_logging - model.start() - else: - raise RuntimeError("Model type should be 'BaseKServeModel'") - if not at_least_one_model_ready and models: - raise NoModelReady(models) + def setup_event_loop(self): + loop = asyncio.get_event_loop() + if self._custom_exception_handler is None: + loop.set_exception_handler(self.default_exception_handler) else: - raise RuntimeError("Unknown model collection type") + loop.set_exception_handler(self._custom_exception_handler) if self.max_asyncio_workers is None: # formula as suggest in https://bugs.python.org/issue35279 self.max_asyncio_workers = min(32, utils.cpu_count() + 4) logger.info(f"Setting max asyncio worker threads as {self.max_asyncio_workers}") - asyncio.get_event_loop().set_default_executor( + loop.set_default_executor( concurrent.futures.ThreadPoolExecutor(max_workers=self.max_asyncio_workers) ) - async def servers_task(): - servers = [self._serve_rest()] - if self.enable_grpc: - servers.append(self._grpc_server.start(self.max_threads)) - await asyncio.gather(*servers) + def register_signal_handler(self): + if sys.platform == "win32": + sig_list = [signal.SIGINT, signal.SIGTERM, signal.SIGBREAK] + else: + sig_list = [signal.SIGINT, signal.SIGTERM, signal.SIGQUIT] + + for sig in sig_list: + signal.signal( + sig, lambda sig, frame: asyncio.create_task(self.stop(sig=sig)) + ) + + async def _servers_task(self): + servers = [self._rest_server.start()] + if self.enable_grpc: + servers.append(self._grpc_server.start(self.max_threads)) + await asyncio.gather(*servers) + + def start(self, models: List[BaseKServeModel]) -> None: + """Start the model server with a set of registered models. - asyncio.run(servers_task()) + Args: + models: a list of models to register to the model server. + """ + self._check_atleast_one_model_is_ready(models) + self.setup_event_loop() + self.register_signal_handler() + asyncio.run(self._servers_task()) - async def stop(self, sig: Optional[int] = None): + async def stop(self, sig: int): """Stop the instances of REST and gRPC model servers. Args: - sig: The signal to stop the server. Default: ``None``. + sig: The signal to stop the server. """ await InferenceClientFactory().close() logger.info("Stopping the model server") - if self._rest_server: - logger.info("Stopping the rest server") - await self._rest_server.stop() if self._grpc_server: logger.info("Stopping the grpc server") await self._grpc_server.stop(sig) @@ -387,3 +369,21 @@ def register_model(self, model: BaseKServeModel): raise Exception("Failed to register model, model.name must be provided.") self.registered_models.update(model) logger.info("Registering model: %s", model.name) + + def _check_atleast_one_model_is_ready(self, models: List[BaseKServeModel]): + if isinstance(models, list): + at_least_one_model_ready = False + for model in models: + if isinstance(model, BaseKServeModel): + if model.ready: + at_least_one_model_ready = True + self.register_model(model) + # pass whether to log request latency into the model + model.enable_latency_logging = self.enable_latency_logging + model.start() + else: + raise RuntimeError("Model type should be 'BaseKServeModel'") + if not at_least_one_model_ready and models: + raise NoModelReady(models) + else: + raise RuntimeError("Unknown model collection type") diff --git a/python/kserve/kserve/models/__init__.py b/python/kserve/kserve/models/__init__.py index d46daa25249..452fe71cddf 100644 --- a/python/kserve/kserve/models/__init__.py +++ b/python/kserve/kserve/models/__init__.py @@ -95,6 +95,7 @@ from kserve.models.v1beta1_pod_spec import V1beta1PodSpec from kserve.models.v1beta1_predictor_extension_spec import V1beta1PredictorExtensionSpec from kserve.models.v1beta1_predictor_spec import V1beta1PredictorSpec +from kserve.models.v1beta1_resource_config import V1beta1ResourceConfig from kserve.models.v1beta1_sk_learn_spec import V1beta1SKLearnSpec from kserve.models.v1beta1_security_config import V1beta1SecurityConfig from kserve.models.v1beta1_service_config import V1beta1ServiceConfig diff --git a/python/kserve/kserve/models/v1beta1_custom_explainer.py b/python/kserve/kserve/models/v1beta1_custom_explainer.py index e280e7207d7..82f0b6f17f7 100644 --- a/python/kserve/kserve/models/v1beta1_custom_explainer.py +++ b/python/kserve/kserve/models/v1beta1_custom_explainer.py @@ -625,7 +625,7 @@ def init_containers(self, init_containers): def node_name(self): """Gets the node_name of this V1beta1CustomExplainer. # noqa: E501 - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :return: The node_name of this V1beta1CustomExplainer. # noqa: E501 :rtype: str @@ -636,7 +636,7 @@ def node_name(self): def node_name(self, node_name): """Sets the node_name of this V1beta1CustomExplainer. - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :param node_name: The node_name of this V1beta1CustomExplainer. # noqa: E501 :type: str diff --git a/python/kserve/kserve/models/v1beta1_custom_predictor.py b/python/kserve/kserve/models/v1beta1_custom_predictor.py index 403cb4d8247..ad309b25a00 100644 --- a/python/kserve/kserve/models/v1beta1_custom_predictor.py +++ b/python/kserve/kserve/models/v1beta1_custom_predictor.py @@ -625,7 +625,7 @@ def init_containers(self, init_containers): def node_name(self): """Gets the node_name of this V1beta1CustomPredictor. # noqa: E501 - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :return: The node_name of this V1beta1CustomPredictor. # noqa: E501 :rtype: str @@ -636,7 +636,7 @@ def node_name(self): def node_name(self, node_name): """Sets the node_name of this V1beta1CustomPredictor. - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :param node_name: The node_name of this V1beta1CustomPredictor. # noqa: E501 :type: str diff --git a/python/kserve/kserve/models/v1beta1_custom_transformer.py b/python/kserve/kserve/models/v1beta1_custom_transformer.py index 06312e1d7c9..f1d4dc0c789 100644 --- a/python/kserve/kserve/models/v1beta1_custom_transformer.py +++ b/python/kserve/kserve/models/v1beta1_custom_transformer.py @@ -625,7 +625,7 @@ def init_containers(self, init_containers): def node_name(self): """Gets the node_name of this V1beta1CustomTransformer. # noqa: E501 - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :return: The node_name of this V1beta1CustomTransformer. # noqa: E501 :rtype: str @@ -636,7 +636,7 @@ def node_name(self): def node_name(self, node_name): """Sets the node_name of this V1beta1CustomTransformer. - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. # noqa: E501 + NodeName indicates in which node this pod is scheduled. If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. This field should not be used to express a desire for the pod to be scheduled on a specific node. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename # noqa: E501 :param node_name: The node_name of this V1beta1CustomTransformer. # noqa: E501 :type: str diff --git a/python/kserve/kserve/models/v1beta1_inference_services_config.py b/python/kserve/kserve/models/v1beta1_inference_services_config.py index 54cba14b5c2..bcf31f2d5c8 100644 --- a/python/kserve/kserve/models/v1beta1_inference_services_config.py +++ b/python/kserve/kserve/models/v1beta1_inference_services_config.py @@ -47,23 +47,38 @@ class V1beta1InferenceServicesConfig(object): and the value is json key in definition. """ openapi_types = { - 'explainers': 'V1beta1ExplainersConfig' + 'explainers': 'V1beta1ExplainersConfig', + 'resource': 'V1beta1ResourceConfig', + 'service_annotation_disallowed_list': 'list[str]', + 'service_label_disallowed_list': 'list[str]' } attribute_map = { - 'explainers': 'explainers' + 'explainers': 'explainers', + 'resource': 'resource', + 'service_annotation_disallowed_list': 'serviceAnnotationDisallowedList', + 'service_label_disallowed_list': 'serviceLabelDisallowedList' } - def __init__(self, explainers=None, local_vars_configuration=None): # noqa: E501 + def __init__(self, explainers=None, resource=None, service_annotation_disallowed_list=None, service_label_disallowed_list=None, local_vars_configuration=None): # noqa: E501 """V1beta1InferenceServicesConfig - a model defined in OpenAPI""" # noqa: E501 if local_vars_configuration is None: local_vars_configuration = Configuration() self.local_vars_configuration = local_vars_configuration self._explainers = None + self._resource = None + self._service_annotation_disallowed_list = None + self._service_label_disallowed_list = None self.discriminator = None self.explainers = explainers + if resource is not None: + self.resource = resource + if service_annotation_disallowed_list is not None: + self.service_annotation_disallowed_list = service_annotation_disallowed_list + if service_label_disallowed_list is not None: + self.service_label_disallowed_list = service_label_disallowed_list @property def explainers(self): @@ -88,6 +103,73 @@ def explainers(self, explainers): self._explainers = explainers + @property + def resource(self): + """Gets the resource of this V1beta1InferenceServicesConfig. # noqa: E501 + + + :return: The resource of this V1beta1InferenceServicesConfig. # noqa: E501 + :rtype: V1beta1ResourceConfig + """ + return self._resource + + @resource.setter + def resource(self, resource): + """Sets the resource of this V1beta1InferenceServicesConfig. + + + :param resource: The resource of this V1beta1InferenceServicesConfig. # noqa: E501 + :type: V1beta1ResourceConfig + """ + + self._resource = resource + + @property + def service_annotation_disallowed_list(self): + """Gets the service_annotation_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + + ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative revisions # noqa: E501 + + :return: The service_annotation_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + :rtype: list[str] + """ + return self._service_annotation_disallowed_list + + @service_annotation_disallowed_list.setter + def service_annotation_disallowed_list(self, service_annotation_disallowed_list): + """Sets the service_annotation_disallowed_list of this V1beta1InferenceServicesConfig. + + ServiceAnnotationDisallowedList is a list of annotations that are not allowed to be propagated to Knative revisions # noqa: E501 + + :param service_annotation_disallowed_list: The service_annotation_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + :type: list[str] + """ + + self._service_annotation_disallowed_list = service_annotation_disallowed_list + + @property + def service_label_disallowed_list(self): + """Gets the service_label_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + + ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions # noqa: E501 + + :return: The service_label_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + :rtype: list[str] + """ + return self._service_label_disallowed_list + + @service_label_disallowed_list.setter + def service_label_disallowed_list(self, service_label_disallowed_list): + """Sets the service_label_disallowed_list of this V1beta1InferenceServicesConfig. + + ServiceLabelDisallowedList is a list of labels that are not allowed to be propagated to Knative revisions # noqa: E501 + + :param service_label_disallowed_list: The service_label_disallowed_list of this V1beta1InferenceServicesConfig. # noqa: E501 + :type: list[str] + """ + + self._service_label_disallowed_list = service_label_disallowed_list + def to_dict(self): """Returns the model properties as a dict""" result = {} diff --git a/python/kserve/kserve/models/v1beta1_ingress_config.py b/python/kserve/kserve/models/v1beta1_ingress_config.py index 29888830ac9..4f7049721fc 100644 --- a/python/kserve/kserve/models/v1beta1_ingress_config.py +++ b/python/kserve/kserve/models/v1beta1_ingress_config.py @@ -51,10 +51,12 @@ class V1beta1IngressConfig(object): 'disable_ingress_creation': 'bool', 'disable_istio_virtual_host': 'bool', 'domain_template': 'str', + 'enable_gateway_api': 'bool', 'ingress_class_name': 'str', 'ingress_domain': 'str', 'ingress_gateway': 'str', 'knative_local_gateway_service': 'str', + 'kserve_ingress_gateway': 'str', 'local_gateway': 'str', 'local_gateway_service': 'str', 'path_template': 'str', @@ -66,17 +68,19 @@ class V1beta1IngressConfig(object): 'disable_ingress_creation': 'disableIngressCreation', 'disable_istio_virtual_host': 'disableIstioVirtualHost', 'domain_template': 'domainTemplate', + 'enable_gateway_api': 'enableGatewayApi', 'ingress_class_name': 'ingressClassName', 'ingress_domain': 'ingressDomain', 'ingress_gateway': 'ingressGateway', 'knative_local_gateway_service': 'knativeLocalGatewayService', + 'kserve_ingress_gateway': 'kserveIngressGateway', 'local_gateway': 'localGateway', 'local_gateway_service': 'localGatewayService', 'path_template': 'pathTemplate', 'url_scheme': 'urlScheme' } - def __init__(self, additional_ingress_domains=None, disable_ingress_creation=None, disable_istio_virtual_host=None, domain_template=None, ingress_class_name=None, ingress_domain=None, ingress_gateway=None, knative_local_gateway_service=None, local_gateway=None, local_gateway_service=None, path_template=None, url_scheme=None, local_vars_configuration=None): # noqa: E501 + def __init__(self, additional_ingress_domains=None, disable_ingress_creation=None, disable_istio_virtual_host=None, domain_template=None, enable_gateway_api=None, ingress_class_name=None, ingress_domain=None, ingress_gateway=None, knative_local_gateway_service=None, kserve_ingress_gateway=None, local_gateway=None, local_gateway_service=None, path_template=None, url_scheme=None, local_vars_configuration=None): # noqa: E501 """V1beta1IngressConfig - a model defined in OpenAPI""" # noqa: E501 if local_vars_configuration is None: local_vars_configuration = Configuration() @@ -86,10 +90,12 @@ def __init__(self, additional_ingress_domains=None, disable_ingress_creation=Non self._disable_ingress_creation = None self._disable_istio_virtual_host = None self._domain_template = None + self._enable_gateway_api = None self._ingress_class_name = None self._ingress_domain = None self._ingress_gateway = None self._knative_local_gateway_service = None + self._kserve_ingress_gateway = None self._local_gateway = None self._local_gateway_service = None self._path_template = None @@ -104,6 +110,8 @@ def __init__(self, additional_ingress_domains=None, disable_ingress_creation=Non self.disable_istio_virtual_host = disable_istio_virtual_host if domain_template is not None: self.domain_template = domain_template + if enable_gateway_api is not None: + self.enable_gateway_api = enable_gateway_api if ingress_class_name is not None: self.ingress_class_name = ingress_class_name if ingress_domain is not None: @@ -112,6 +120,8 @@ def __init__(self, additional_ingress_domains=None, disable_ingress_creation=Non self.ingress_gateway = ingress_gateway if knative_local_gateway_service is not None: self.knative_local_gateway_service = knative_local_gateway_service + if kserve_ingress_gateway is not None: + self.kserve_ingress_gateway = kserve_ingress_gateway if local_gateway is not None: self.local_gateway = local_gateway if local_gateway_service is not None: @@ -205,6 +215,27 @@ def domain_template(self, domain_template): self._domain_template = domain_template + @property + def enable_gateway_api(self): + """Gets the enable_gateway_api of this V1beta1IngressConfig. # noqa: E501 + + + :return: The enable_gateway_api of this V1beta1IngressConfig. # noqa: E501 + :rtype: bool + """ + return self._enable_gateway_api + + @enable_gateway_api.setter + def enable_gateway_api(self, enable_gateway_api): + """Sets the enable_gateway_api of this V1beta1IngressConfig. + + + :param enable_gateway_api: The enable_gateway_api of this V1beta1IngressConfig. # noqa: E501 + :type: bool + """ + + self._enable_gateway_api = enable_gateway_api + @property def ingress_class_name(self): """Gets the ingress_class_name of this V1beta1IngressConfig. # noqa: E501 @@ -289,6 +320,27 @@ def knative_local_gateway_service(self, knative_local_gateway_service): self._knative_local_gateway_service = knative_local_gateway_service + @property + def kserve_ingress_gateway(self): + """Gets the kserve_ingress_gateway of this V1beta1IngressConfig. # noqa: E501 + + + :return: The kserve_ingress_gateway of this V1beta1IngressConfig. # noqa: E501 + :rtype: str + """ + return self._kserve_ingress_gateway + + @kserve_ingress_gateway.setter + def kserve_ingress_gateway(self, kserve_ingress_gateway): + """Sets the kserve_ingress_gateway of this V1beta1IngressConfig. + + + :param kserve_ingress_gateway: The kserve_ingress_gateway of this V1beta1IngressConfig. # noqa: E501 + :type: str + """ + + self._kserve_ingress_gateway = kserve_ingress_gateway + @property def local_gateway(self): """Gets the local_gateway of this V1beta1IngressConfig. # noqa: E501 diff --git a/python/kserve/kserve/models/v1beta1_local_model_config.py b/python/kserve/kserve/models/v1beta1_local_model_config.py index f6b55844e9a..d1bcb0d5d48 100644 --- a/python/kserve/kserve/models/v1beta1_local_model_config.py +++ b/python/kserve/kserve/models/v1beta1_local_model_config.py @@ -48,6 +48,7 @@ class V1beta1LocalModelConfig(object): """ openapi_types = { 'default_job_image': 'str', + 'disable_volume_management': 'bool', 'enabled': 'bool', 'fs_group': 'int', 'job_namespace': 'str', @@ -57,6 +58,7 @@ class V1beta1LocalModelConfig(object): attribute_map = { 'default_job_image': 'defaultJobImage', + 'disable_volume_management': 'disableVolumeManagement', 'enabled': 'enabled', 'fs_group': 'fsGroup', 'job_namespace': 'jobNamespace', @@ -64,13 +66,14 @@ class V1beta1LocalModelConfig(object): 'reconcilation_frequency_in_secs': 'reconcilationFrequencyInSecs' } - def __init__(self, default_job_image=None, enabled=False, fs_group=None, job_namespace='', job_ttl_seconds_after_finished=None, reconcilation_frequency_in_secs=None, local_vars_configuration=None): # noqa: E501 + def __init__(self, default_job_image=None, disable_volume_management=None, enabled=False, fs_group=None, job_namespace='', job_ttl_seconds_after_finished=None, reconcilation_frequency_in_secs=None, local_vars_configuration=None): # noqa: E501 """V1beta1LocalModelConfig - a model defined in OpenAPI""" # noqa: E501 if local_vars_configuration is None: local_vars_configuration = Configuration() self.local_vars_configuration = local_vars_configuration self._default_job_image = None + self._disable_volume_management = None self._enabled = None self._fs_group = None self._job_namespace = None @@ -80,6 +83,8 @@ def __init__(self, default_job_image=None, enabled=False, fs_group=None, job_nam if default_job_image is not None: self.default_job_image = default_job_image + if disable_volume_management is not None: + self.disable_volume_management = disable_volume_management self.enabled = enabled if fs_group is not None: self.fs_group = fs_group @@ -110,6 +115,27 @@ def default_job_image(self, default_job_image): self._default_job_image = default_job_image + @property + def disable_volume_management(self): + """Gets the disable_volume_management of this V1beta1LocalModelConfig. # noqa: E501 + + + :return: The disable_volume_management of this V1beta1LocalModelConfig. # noqa: E501 + :rtype: bool + """ + return self._disable_volume_management + + @disable_volume_management.setter + def disable_volume_management(self, disable_volume_management): + """Sets the disable_volume_management of this V1beta1LocalModelConfig. + + + :param disable_volume_management: The disable_volume_management of this V1beta1LocalModelConfig. # noqa: E501 + :type: bool + """ + + self._disable_volume_management = disable_volume_management + @property def enabled(self): """Gets the enabled of this V1beta1LocalModelConfig. # noqa: E501 diff --git a/python/kserve/kserve/models/v1beta1_resource_config.py b/python/kserve/kserve/models/v1beta1_resource_config.py new file mode 100644 index 00000000000..3e2456ccfc4 --- /dev/null +++ b/python/kserve/kserve/models/v1beta1_resource_config.py @@ -0,0 +1,212 @@ +# Copyright 2023 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# coding: utf-8 + +""" + KServe + + Python SDK for KServe # noqa: E501 + + The version of the OpenAPI document: v0.1 + Generated by: https://openapi-generator.tech +""" + + +import pprint +import re # noqa: F401 + +import six + +from kserve.configuration import Configuration + + +class V1beta1ResourceConfig(object): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + """ + Attributes: + openapi_types (dict): The key is attribute name + and the value is attribute type. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + """ + openapi_types = { + 'cpu_limit': 'str', + 'cpu_request': 'str', + 'memory_limit': 'str', + 'memory_request': 'str' + } + + attribute_map = { + 'cpu_limit': 'cpuLimit', + 'cpu_request': 'cpuRequest', + 'memory_limit': 'memoryLimit', + 'memory_request': 'memoryRequest' + } + + def __init__(self, cpu_limit=None, cpu_request=None, memory_limit=None, memory_request=None, local_vars_configuration=None): # noqa: E501 + """V1beta1ResourceConfig - a model defined in OpenAPI""" # noqa: E501 + if local_vars_configuration is None: + local_vars_configuration = Configuration() + self.local_vars_configuration = local_vars_configuration + + self._cpu_limit = None + self._cpu_request = None + self._memory_limit = None + self._memory_request = None + self.discriminator = None + + if cpu_limit is not None: + self.cpu_limit = cpu_limit + if cpu_request is not None: + self.cpu_request = cpu_request + if memory_limit is not None: + self.memory_limit = memory_limit + if memory_request is not None: + self.memory_request = memory_request + + @property + def cpu_limit(self): + """Gets the cpu_limit of this V1beta1ResourceConfig. # noqa: E501 + + + :return: The cpu_limit of this V1beta1ResourceConfig. # noqa: E501 + :rtype: str + """ + return self._cpu_limit + + @cpu_limit.setter + def cpu_limit(self, cpu_limit): + """Sets the cpu_limit of this V1beta1ResourceConfig. + + + :param cpu_limit: The cpu_limit of this V1beta1ResourceConfig. # noqa: E501 + :type: str + """ + + self._cpu_limit = cpu_limit + + @property + def cpu_request(self): + """Gets the cpu_request of this V1beta1ResourceConfig. # noqa: E501 + + + :return: The cpu_request of this V1beta1ResourceConfig. # noqa: E501 + :rtype: str + """ + return self._cpu_request + + @cpu_request.setter + def cpu_request(self, cpu_request): + """Sets the cpu_request of this V1beta1ResourceConfig. + + + :param cpu_request: The cpu_request of this V1beta1ResourceConfig. # noqa: E501 + :type: str + """ + + self._cpu_request = cpu_request + + @property + def memory_limit(self): + """Gets the memory_limit of this V1beta1ResourceConfig. # noqa: E501 + + + :return: The memory_limit of this V1beta1ResourceConfig. # noqa: E501 + :rtype: str + """ + return self._memory_limit + + @memory_limit.setter + def memory_limit(self, memory_limit): + """Sets the memory_limit of this V1beta1ResourceConfig. + + + :param memory_limit: The memory_limit of this V1beta1ResourceConfig. # noqa: E501 + :type: str + """ + + self._memory_limit = memory_limit + + @property + def memory_request(self): + """Gets the memory_request of this V1beta1ResourceConfig. # noqa: E501 + + + :return: The memory_request of this V1beta1ResourceConfig. # noqa: E501 + :rtype: str + """ + return self._memory_request + + @memory_request.setter + def memory_request(self, memory_request): + """Sets the memory_request of this V1beta1ResourceConfig. + + + :param memory_request: The memory_request of this V1beta1ResourceConfig. # noqa: E501 + :type: str + """ + + self._memory_request = memory_request + + def to_dict(self): + """Returns the model properties as a dict""" + result = {} + + for attr, _ in six.iteritems(self.openapi_types): + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list(map( + lambda x: x.to_dict() if hasattr(x, "to_dict") else x, + value + )) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict(map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") else item, + value.items() + )) + else: + result[attr] = value + + return result + + def to_str(self): + """Returns the string representation of the model""" + return pprint.pformat(self.to_dict()) + + def __repr__(self): + """For `print` and `pprint`""" + return self.to_str() + + def __eq__(self, other): + """Returns true if both objects are equal""" + if not isinstance(other, V1beta1ResourceConfig): + return False + + return self.to_dict() == other.to_dict() + + def __ne__(self, other): + """Returns true if both objects are not equal""" + if not isinstance(other, V1beta1ResourceConfig): + return True + + return self.to_dict() != other.to_dict() diff --git a/python/kserve/kserve/protocol/dataplane.py b/python/kserve/kserve/protocol/dataplane.py index 4c1300cf593..6badb7b24f4 100644 --- a/python/kserve/kserve/protocol/dataplane.py +++ b/python/kserve/kserve/protocol/dataplane.py @@ -35,7 +35,7 @@ from ..utils.inference_client_factory import InferenceClientFactory from ..utils.utils import create_response_cloudevent, is_structured_cloudevent from .infer_type import InferRequest, InferResponse -from .rest.openai import OpenAIModel +from .rest.openai import OpenAICompletionModel JSON_HEADERS = [ "application/json", @@ -258,7 +258,7 @@ async def ready(self) -> bool: self.predictor_config.predictor_base_url ) else: - return await self._inference_rest_client.is_server_ready( + return await self.rest_client.is_server_ready( self.predictor_config.predictor_base_url ) return True @@ -432,8 +432,8 @@ async def infer( # call model locally or remote model workers response_headers = {} model = await self.get_model(model_name) - if isinstance(model, OpenAIModel): - error_msg = f"Model {model_name} is of type OpenAIModel. It does not support the infer method." + if isinstance(model, OpenAICompletionModel): + error_msg = f"Model {model_name} is of type OpenAICompletionModel. It does not support the infer method." raise InvalidInput(reason=error_msg) if not isinstance(model, InferenceModel): raise ValueError( @@ -466,9 +466,9 @@ async def explain( # call model locally or remote model workers response_headers = headers if headers else {} model = await self.get_model(model_name) - if isinstance(model, OpenAIModel): + if isinstance(model, OpenAICompletionModel): logger.warning( - f"Model {model_name} is of type OpenAIModel. It does not support the explain method." + f"Model {model_name} is of type OpenAICompletionModel. It does not support the explain method." " A request exercised this path and will cause a server crash." ) if not isinstance(model, InferenceModel): diff --git a/python/kserve/kserve/protocol/grpc/server.py b/python/kserve/kserve/protocol/grpc/server.py index 0b7a3905228..28b41cb962b 100644 --- a/python/kserve/kserve/protocol/grpc/server.py +++ b/python/kserve/kserve/protocol/grpc/server.py @@ -65,6 +65,7 @@ async def start(self, max_workers): listen_addr = f"[::]:{self._port}" self._server.add_insecure_port(listen_addr) + logger.info(f"Starting gRPC server with {max_workers} workers") logger.info("Starting gRPC server on %s", listen_addr) await self._server.start() await self._server.wait_for_termination() diff --git a/python/kserve/kserve/protocol/rest/openai/__init__.py b/python/kserve/kserve/protocol/rest/openai/__init__.py index ea1412b9d31..9eca9bf48f8 100644 --- a/python/kserve/kserve/protocol/rest/openai/__init__.py +++ b/python/kserve/kserve/protocol/rest/openai/__init__.py @@ -16,7 +16,10 @@ ChatPrompt, CompletionRequest, ChatCompletionRequest, + EmbeddingRequest, OpenAIModel, + OpenAICompletionModel, + OpenAIEmbeddingModel, ) from .openai_proxy_model import OpenAIProxyModel @@ -26,9 +29,12 @@ __all__ = [ "OpenAIModel", "OpenAIChatAdapterModel", + "OpenAICompletionModel", + "OpenAIEmbeddingModel", "OpenAIProxyModel", "ChatPrompt", "CompletionRequest", "ChatCompletionRequest", "ChatCompletionRequestMessage", + "EmbeddingRequest", ] diff --git a/python/kserve/kserve/protocol/rest/openai/dataplane.py b/python/kserve/kserve/protocol/rest/openai/dataplane.py index 07ba3abc5ac..f9aa24c571c 100644 --- a/python/kserve/kserve/protocol/rest/openai/dataplane.py +++ b/python/kserve/kserve/protocol/rest/openai/dataplane.py @@ -28,9 +28,20 @@ from kserve.protocol.rest.openai.types.openapi import ( CreateCompletionResponse as Completion, ) +from kserve.protocol.rest.openai.types.openapi import CreateEmbeddingRequest +from kserve.protocol.rest.openai.types.openapi import ( + CreateEmbeddingResponse as Embedding, +) from ...dataplane import DataPlane -from .openai_model import ChatCompletionRequest, CompletionRequest, OpenAIModel +from .openai_model import ( + ChatCompletionRequest, + CompletionRequest, + EmbeddingRequest, + OpenAIModel, + OpenAICompletionModel, + OpenAIEmbeddingModel, +) class OpenAIDataPlane(DataPlane): @@ -57,7 +68,7 @@ async def create_completion( InvalidInput: An error when the body bytes can't be decoded as JSON. """ model = await self.get_model(model_name) - if not isinstance(model, OpenAIModel): + if not isinstance(model, OpenAICompletionModel): raise RuntimeError(f"Model {model_name} does not support completion") completion_request = CompletionRequest( @@ -88,7 +99,7 @@ async def create_chat_completion( InvalidInput: An error when the body bytes can't be decoded as JSON. """ model = await self.get_model(model_name) - if not isinstance(model, OpenAIModel): + if not isinstance(model, OpenAICompletionModel): raise RuntimeError(f"Model {model_name} does not support chat completion") completion_request = ChatCompletionRequest( @@ -99,6 +110,37 @@ async def create_chat_completion( ) return await model.create_chat_completion(completion_request) + async def create_embedding( + self, + model_name: str, + request: CreateEmbeddingRequest, + headers: Headers, + response: Response, + ) -> Embedding: + """Creates an embedding vector representing the input text. + + Args: + model_name (str): Model name. + request (CreateEmbeddingRequest): Params to create the embedding. + headers: (Optional[Dict[str, str]]): Request headers. + + Returns: + response: A non-streaming embedding response + + Raises: + InvalidInput: An error when the body bytes can't be decoded as JSON. + """ + model = await self.get_model(model_name) + if not isinstance(model, OpenAIEmbeddingModel): + raise RuntimeError(f"Model {model_name} does not support embeddings") + + embedding_request = EmbeddingRequest( + request_id=headers.get("x-request-id", None), + params=request, + context={"headers": dict(headers), "response": response}, + ) + return await model.create_embedding(embedding_request) + async def models(self) -> List[OpenAIModel]: """Retrieve a list of models diff --git a/python/kserve/kserve/protocol/rest/openai/endpoints.py b/python/kserve/kserve/protocol/rest/openai/endpoints.py index 7e11250b577..c00c6b14a8c 100644 --- a/python/kserve/kserve/protocol/rest/openai/endpoints.py +++ b/python/kserve/kserve/protocol/rest/openai/endpoints.py @@ -25,6 +25,7 @@ from kserve.protocol.rest.openai.types.openapi import ( CreateChatCompletionRequest, CreateCompletionRequest, + CreateEmbeddingRequest, ListModelsResponse, Model, ) @@ -41,6 +42,7 @@ CreateCompletionRequestAdapter = TypeAdapter(CreateCompletionRequest) ChatCompletionRequestAdapter = TypeAdapter(CreateChatCompletionRequest) +EmbeddingRequestAdapter = TypeAdapter(CreateEmbeddingRequest) class OpenAIEndpoints: @@ -58,8 +60,8 @@ async def create_completion( Args: raw_request (Request): fastapi request object, - model_name (str): Model name. request_body (CompletionCreateParams): Completion params body. + response (Response): fastapi response object Returns: InferenceResponse: Inference response object. @@ -102,8 +104,8 @@ async def create_chat_completion( Args: raw_request (Request): fastapi request object, - model_name (str): Model name. request_body (ChatCompletionRequestAdapter): Chat completion params body. + response (Response): fastapi response object Returns: InferenceResponse: Inference response object. @@ -137,6 +139,41 @@ async def stream_results() -> AsyncGenerator[str, None]: else: return completion + async def create_embedding( + self, + raw_request: Request, + request_body: CreateEmbeddingRequest, + response: Response, + ) -> Response: + """Create embedding handler. + + Args: + raw_request (Request): fastapi request object, + request_body (CreateEmbeddingRequest): Embedding params body. + response (Response): fastapi response object + + Returns: + InferenceResponse: Inference response object. + """ + try: + params = EmbeddingRequestAdapter.validate_python(request_body) + except ValidationError as e: + raise RequestValidationError(errors=e.errors()) + params = request_body + model_name = params.model + model_ready = await self.dataplane.model_ready(model_name) + + if not model_ready: + raise ModelNotReady(model_name) + + request_headers = raw_request.headers + return await self.dataplane.create_embedding( + model_name=model_name, + request=request_body, + headers=request_headers, + response=response, + ) + async def models( self, ) -> ListModelsResponse: @@ -180,6 +217,13 @@ def register_openai_endpoints(app: FastAPI, dataplane: OpenAIDataPlane): response_model_exclude_none=True, response_model_exclude_unset=True, ) + openai_router.add_api_route( + r"/v1/embeddings", + endpoints.create_embedding, + methods=["POST"], + response_model_exclude_none=True, + response_model_exclude_unset=True, + ) openai_router.add_api_route( r"/v1/models", endpoints.models, diff --git a/python/kserve/kserve/protocol/rest/openai/openai_chat_adapter_model.py b/python/kserve/kserve/protocol/rest/openai/openai_chat_adapter_model.py index 83002c3b854..f7ecef64252 100644 --- a/python/kserve/kserve/protocol/rest/openai/openai_chat_adapter_model.py +++ b/python/kserve/kserve/protocol/rest/openai/openai_chat_adapter_model.py @@ -35,7 +35,7 @@ from ....errors import InvalidInput from .openai_model import ( - OpenAIModel, + OpenAICompletionModel, ChatPrompt, CompletionRequest, ChatCompletionRequest, @@ -43,7 +43,7 @@ ) -class OpenAIChatAdapterModel(OpenAIModel): +class OpenAIChatAdapterModel(OpenAICompletionModel): """ A helper on top the OpenAI model that automatically maps chat completion requests (/v1/chat/completions) to completion requests (/v1/completions). diff --git a/python/kserve/kserve/protocol/rest/openai/openai_model.py b/python/kserve/kserve/protocol/rest/openai/openai_model.py index 0a169d04a06..5a92545ddec 100644 --- a/python/kserve/kserve/protocol/rest/openai/openai_model.py +++ b/python/kserve/kserve/protocol/rest/openai/openai_model.py @@ -24,6 +24,8 @@ Completion, CreateChatCompletionRequest, CreateCompletionRequest, + CreateEmbeddingRequest, + Embedding, ) from ....model import BaseKServeModel @@ -34,27 +36,29 @@ class ChatPrompt(BaseModel): prompt: str -class BaseCompletionRequest(BaseModel): +class BaseOpenAIRequest(BaseModel): request_id: Optional[str] = None context: Optional[Dict[str, Any]] = None # headers can go in here - params: Union[CreateCompletionRequest, CreateChatCompletionRequest] + params: Union[ + CreateCompletionRequest, CreateChatCompletionRequest, CreateEmbeddingRequest + ] -class CompletionRequest(BaseCompletionRequest): +class CompletionRequest(BaseOpenAIRequest): params: CreateCompletionRequest -class ChatCompletionRequest(BaseCompletionRequest): +class ChatCompletionRequest(BaseOpenAIRequest): params: CreateChatCompletionRequest +class EmbeddingRequest(BaseOpenAIRequest): + params: CreateEmbeddingRequest + + class OpenAIModel(BaseKServeModel): """ - An abstract model with methods for implementing OpenAI's completions (v1/completions) - and chat completions (v1/chat/completions) endpoints. - - Users should extend this model and implement the abstract methods in order to expose - these endpoints. + An abstract model with methods for implementing OpenAI's endpoints. """ def __init__(self, name: str): @@ -64,6 +68,16 @@ def __init__(self, name: str): # Assume the model is ready self.ready = True + +class OpenAICompletionModel(OpenAIModel): + """ + An abstract model with methods for implementing OpenAI's completions (v1/completions) + and chat completions (v1/chat/completions) endpoints. + + Users should extend this model and implement the abstract methods in order to expose + these endpoints. + """ + @abstractmethod async def create_completion( self, request: CompletionRequest @@ -77,6 +91,20 @@ async def create_chat_completion( pass +class OpenAIEmbeddingModel(OpenAIModel): + """ + An abstract model with a method for implementing OpenAI's embeddings (/v1/embeddings) + endpoint. + + Users should extend this model and implement the abstract methods in order to expose + these endpoints. + """ + + @abstractmethod + async def create_embedding(self, request: EmbeddingRequest) -> Embedding: + pass + + class AsyncMappingIterator: def __init__( self, diff --git a/python/kserve/kserve/protocol/rest/openai/openai_proxy_model.py b/python/kserve/kserve/protocol/rest/openai/openai_proxy_model.py index 59ec4ac9c23..ae3d9d95aee 100644 --- a/python/kserve/kserve/protocol/rest/openai/openai_proxy_model.py +++ b/python/kserve/kserve/protocol/rest/openai/openai_proxy_model.py @@ -22,8 +22,8 @@ from .openai_model import ( - BaseCompletionRequest, - OpenAIModel, + BaseOpenAIRequest, + OpenAICompletionModel, AsyncMappingIterator, CompletionRequest, ChatCompletionRequest, @@ -91,7 +91,7 @@ async def wrapper(*args, **kwargs): return wrapper -class OpenAIProxyModel(OpenAIModel): +class OpenAIProxyModel(OpenAICompletionModel): """ An implementation of OpenAIModel that proxies requests to a backend server exposing Open AI endpoints. @@ -218,7 +218,7 @@ def _handle_chat_completion_chunk( return chat_completion_chunk def _build_request( - self, endpoint: str, request: BaseCompletionRequest + self, endpoint: str, request: BaseOpenAIRequest ) -> httpx.Request: if request.context and "upstream_headers" in request.context: diff --git a/python/kserve/kserve/protocol/rest/openai/types/__init__.py b/python/kserve/kserve/protocol/rest/openai/types/__init__.py index 3400c917014..fae8def9ceb 100644 --- a/python/kserve/kserve/protocol/rest/openai/types/__init__.py +++ b/python/kserve/kserve/protocol/rest/openai/types/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union +from typing import Union, List from kserve.protocol.rest.openai.types.openapi import ( ChatCompletionRequestAssistantMessage, @@ -40,6 +40,11 @@ from kserve.protocol.rest.openai.types.openapi import ( CreateCompletionResponse as Completion, ) +from kserve.protocol.rest.openai.types.openapi import CreateEmbeddingRequest +from kserve.protocol.rest.openai.types.openapi import ( + CreateEmbeddingResponse as Embedding, + Embedding as BaseEmbeddingObject, +) from kserve.protocol.rest.openai.types.openapi import Logprobs from kserve.protocol.rest.openai.types.openapi import ( Logprobs2 as ChatCompletionChoiceLogprobs, @@ -56,6 +61,12 @@ ChatCompletionRequestFunctionMessage, ] + +# The autogenerated OpenAPI specification doesn't seem to include the base64 encoding option. Add it manually. +class EmbeddingObject(BaseEmbeddingObject): + embedding: Union[List[float], str] + + __all__ = [ "ChatCompletion", "ChatCompletionChoice", @@ -76,6 +87,9 @@ "CompletionChoice", "CreateChatCompletionRequest", "CreateCompletionRequest", + "CreateEmbeddingRequest", + "Embedding", + "EmbeddingObject", "ErrorResponse", "Logprobs", "TopLogprob", diff --git a/python/kserve/kserve/protocol/rest/server.py b/python/kserve/kserve/protocol/rest/server.py index b7d89e9a2f7..15d89b6003e 100644 --- a/python/kserve/kserve/protocol/rest/server.py +++ b/python/kserve/kserve/protocol/rest/server.py @@ -40,7 +40,7 @@ server_not_ready_handler, unsupported_protocol_error_handler, ) -from kserve.logging import trace_logger +from kserve.logging import trace_logger, logger from kserve.protocol.dataplane import DataPlane from .openai.config import maybe_register_openai_endpoints @@ -59,24 +59,32 @@ def timing(self, metric_name, timing, tags): trace_logger.info(f"{metric_name}: {timing} {tags}") -class _NoSignalUvicornServer(uvicorn.Server): - def install_signal_handlers(self) -> None: - pass - - class RESTServer: def __init__( self, app: FastAPI, data_plane: DataPlane, model_repository_extension: ModelRepositoryExtension, + http_port: int, + log_config: Optional[Union[str, Dict]] = None, + access_log_format: Optional[str] = None, + workers: int = 1, ): self.app = app self.dataplane = data_plane self.model_repository_extension = model_repository_extension + self.access_log_format = access_log_format + self._server = uvicorn.Server( + config=uvicorn.Config( + app="kserve.model_server:app", + host="0.0.0.0", + log_config=log_config, + port=http_port, + workers=workers, + ) + ) - def create_application(self): - """Create a KServe ModelServer application with API routes.""" + def _register_endpoints(self): root_router = APIRouter() root_router.add_api_route(r"/", self.dataplane.live) root_router.add_api_route(r"/metrics", metrics_handler, methods=["GET"]) @@ -88,7 +96,7 @@ def create_application(self): # REST server. maybe_register_openai_endpoints(self.app, self.dataplane.model_registry) - # Add exception handlers + def _add_exception_handlers(self): self.app.add_exception_handler(InvalidInput, invalid_input_handler) self.app.add_exception_handler(InferenceError, inference_error_handler) self.app.add_exception_handler(ModelNotFound, model_not_found_handler) @@ -103,32 +111,13 @@ def create_application(self): self.app.add_exception_handler(ServerNotReady, server_not_ready_handler) self.app.add_exception_handler(Exception, generic_exception_handler) - -class UvicornServer: - def __init__( - self, - app: FastAPI, - http_port: int, - data_plane: DataPlane, - model_repository_extension, - log_config: Optional[Union[str, Dict]] = None, - access_log_format: Optional[str] = None, - workers: int = 1, - ): - super().__init__() - rest_server = RESTServer(app, data_plane, model_repository_extension) - rest_server.create_application() - app.add_middleware( + def _add_middlewares(self): + self.app.add_middleware( TimingMiddleware, client=PrintTimings(), - metric_namer=StarletteScopeToName(prefix="kserve.io", starlette_app=app), - ) - self.cfg = uvicorn.Config( - app="kserve.model_server:app", - host="0.0.0.0", - log_config=log_config, - port=http_port, - workers=workers, + metric_namer=StarletteScopeToName( + prefix="kserve.io", starlette_app=self.app + ), ) # More context in https://github.com/encode/uvicorn/pull/947 @@ -136,22 +125,25 @@ def __init__( # to change the access log format, and hence the Uvicorn upstream devs # chose to create a custom middleware for this. # The allowed log format is specified in https://github.com/Kludex/asgi-logger#usage - if access_log_format: + if self.access_log_format: from asgi_logger import AccessLoggerMiddleware # As indicated by the asgi-logger docs, we need to clear/unset # any setting for uvicorn.access to avoid log duplicates. logging.getLogger("uvicorn.access").handlers = [] - app.add_middleware(AccessLoggerMiddleware, format=access_log_format) + self.app.add_middleware( + AccessLoggerMiddleware, format=self.access_log_format + ) # The asgi-logger settings don't set propagate to False, # so we get duplicates if we don't set it explicitly. logging.getLogger("access").propagate = False - self.server = _NoSignalUvicornServer(config=self.cfg) - - async def run(self): - await self.server.serve() - - async def stop(self, sig: Optional[int] = None): - if self.server: - self.server.handle_exit(sig=sig, frame=None) + def create_application(self): + self._add_middlewares() + self._register_endpoints() + self._add_exception_handlers() + + async def start(self): + self.create_application() + logger.info(f"Starting uvicorn with {self._server.config.workers} workers") + await self._server.serve() diff --git a/python/kserve/kserve/storage/storage.py b/python/kserve/kserve/storage/storage.py index 2f19525409f..8aed6c0c01d 100644 --- a/python/kserve/kserve/storage/storage.py +++ b/python/kserve/kserve/storage/storage.py @@ -176,6 +176,17 @@ def get_S3_config(): if accelerate: c = c.merge(Config(s3={"use_accelerate_endpoint": accelerate})) + # NOTE: If endpoint_url provided is legacy ("https://s3.amazonaws.com") and region is not global (us-east-1), set to virtual addressing style + # So that request would not return PermanentRedirect due to region not in the endpoint url + # AWS SDK retries under the hood to set the correct region when the valid virtual addressing style endpoint url is provided + endpoint_url = os.getenv("AWS_ENDPOINT_URL") + region = os.getenv("AWS_DEFAULT_REGION") + if endpoint_url == "https://s3.amazonaws.com" and region not in ( + None, + "us-east-1", + ): + c = c.merge(Config(s3={"addressing_style": "virtual"})) + return c @staticmethod @@ -258,8 +269,11 @@ def _download_s3(uri, temp_dir: str) -> str: bucket_path_last_part ): target_key = object_last_path + elif obj.key.startswith(bucket_path): + # remove only the bucket_path prefix + target_key = obj.key[len(bucket_path) :].lstrip("/") else: - target_key = obj.key.replace(bucket_path, "").lstrip("/") + target_key = obj.key target = f"{temp_dir}/{target_key}" if not os.path.exists(os.path.dirname(target)): diff --git a/python/kserve/kserve/storage/test/test_s3_storage.py b/python/kserve/kserve/storage/test/test_s3_storage.py index 58172171ff5..baa63ae69e9 100644 --- a/python/kserve/kserve/storage/test/test_s3_storage.py +++ b/python/kserve/kserve/storage/test/test_s3_storage.py @@ -253,6 +253,17 @@ def test_get_S3_config(): == USE_ACCELERATE_CONFIG.s3["use_accelerate_endpoint"] ) + # tests legacy endpoint url + with mock.patch.dict( + os.environ, + { + "AWS_ENDPOINT_URL": "https://s3.amazonaws.com", + "AWS_DEFAULT_REGION": "eu-west-1", + }, + ): + config8 = Storage.get_S3_config() + assert config8.s3["addressing_style"] == VIRTUAL_CONFIG.s3["addressing_style"] + def test_update_with_storage_spec_s3(monkeypatch): # save the environment and restore it after the test to avoid mutating it @@ -318,3 +329,33 @@ def test_target_startswith_parent_folder_name(mock_storage): == expected_call_args_list("test/artifacts/model", "dest_path", paths)[0] ) mock_boto3_bucket.objects.filter.assert_called_with(Prefix="test/artifacts/model") + + +@mock.patch("boto3.resource") +def test_file_name_preservation(mock_storage): + # given + bucket_name = "local-model" + paths = ["MLmodel"] + object_paths = ["model/" + p for p in paths] + expected_file_name = "MLmodel" # Expected file name after download + + # when + mock_boto3_bucket = create_mock_boto3_bucket(mock_storage, object_paths) + Storage._download_s3(f"s3://{bucket_name}/model", "dest_path") + + # then + arg_list = get_call_args(mock_boto3_bucket.download_file.call_args_list) + assert len(arg_list) == 1 # Ensure only one file was downloaded + downloaded_source, downloaded_target = arg_list[0] + + # Check if the source S3 key matches the original object key + assert ( + downloaded_source == object_paths[0] + ), f"Expected {object_paths[0]}, got {downloaded_source}" + + # Check if the target file path ends with the expected file name + assert downloaded_target.endswith( + expected_file_name + ), f"Expected file name to end with {expected_file_name}, got {downloaded_target}" + + mock_boto3_bucket.objects.filter.assert_called_with(Prefix="model") diff --git a/python/kserve/kserve/utils/inference_client_factory.py b/python/kserve/kserve/utils/inference_client_factory.py index 5fe1bef779b..94dee31266a 100644 --- a/python/kserve/kserve/utils/inference_client_factory.py +++ b/python/kserve/kserve/utils/inference_client_factory.py @@ -14,12 +14,14 @@ from typing import Optional from ..inference_client import InferenceGRPCClient, InferenceRESTClient, RESTConfig +from .utils import is_v2 class InferenceClientFactory: _instance = None _grpc_client: Optional[InferenceGRPCClient] = None - _rest_client: Optional[InferenceRESTClient] = None + _rest_v1_client: Optional[InferenceRESTClient] = None + _rest_v2_client: Optional[InferenceRESTClient] = None def __new__(cls): if cls._instance is None: @@ -32,12 +34,18 @@ def get_grpc_client(self, url: str, **kwargs) -> InferenceGRPCClient: return self._grpc_client def get_rest_client(self, config: RESTConfig = None) -> InferenceRESTClient: - if self._rest_client is None: - self._rest_client = InferenceRESTClient(config) - return self._rest_client + if config and is_v2(config.protocol): + if self._rest_v2_client is None: + self._rest_v2_client = InferenceRESTClient(config) + return self._rest_v2_client + if self._rest_v1_client is None: + self._rest_v1_client = InferenceRESTClient(config) + return self._rest_v1_client async def close(self): if self._grpc_client is not None: await self._grpc_client.close() - if self._rest_client is not None: - await self._rest_client.close() + if self._rest_v1_client is not None: + await self._rest_v1_client.close() + if self._rest_v2_client is not None: + await self._rest_v2_client.close() diff --git a/python/kserve/poetry.lock b/python/kserve/poetry.lock index d4bf5e40790..17acdfdea3c 100644 --- a/python/kserve/poetry.lock +++ b/python/kserve/poetry.lock @@ -13,112 +13,112 @@ files = [ [[package]] name = "aiohttp" -version = "3.10.5" +version = "3.10.11" description = "Async http client/server framework (asyncio)" optional = true python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5077b1a5f40ffa3ba1f40d537d3bec4383988ee51fbba6b74aa8fb1bc466599e"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d6a14a4d93b5b3c2891fca94fa9d41b2322a68194422bef0dd5ec1e57d7d298"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffbfde2443696345e23a3c597049b1dd43049bb65337837574205e7368472177"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20b3d9e416774d41813bc02fdc0663379c01817b0874b932b81c7f777f67b217"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b943011b45ee6bf74b22245c6faab736363678e910504dd7531a58c76c9015a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48bc1d924490f0d0b3658fe5c4b081a4d56ebb58af80a6729d4bd13ea569797a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e12eb3f4b1f72aaaf6acd27d045753b18101524f72ae071ae1c91c1cd44ef115"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14ebc419a568c2eff3c1ed35f634435c24ead2fe19c07426af41e7adb68713a"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72b191cdf35a518bfc7ca87d770d30941decc5aaf897ec8b484eb5cc8c7706f3"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ab2328a61fdc86424ee540d0aeb8b73bbcad7351fb7cf7a6546fc0bcffa0038"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa93063d4af05c49276cf14e419550a3f45258b6b9d1f16403e777f1addf4519"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30283f9d0ce420363c24c5c2421e71a738a2155f10adbb1a11a4d4d6d2715cfc"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e5358addc8044ee49143c546d2182c15b4ac3a60be01c3209374ace05af5733d"}, + {file = "aiohttp-3.10.11-cp310-cp310-win32.whl", hash = "sha256:e1ffa713d3ea7cdcd4aea9cddccab41edf6882fa9552940344c44e59652e1120"}, + {file = "aiohttp-3.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:778cbd01f18ff78b5dd23c77eb82987ee4ba23408cbed233009fd570dda7e674"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:80ff08556c7f59a7972b1e8919f62e9c069c33566a6d28586771711e0eea4f07"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c8f96e9ee19f04c4914e4e7a42a60861066d3e1abf05c726f38d9d0a466e695"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb8601394d537da9221947b5d6e62b064c9a43e88a1ecd7414d21a1a6fba9c24"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea224cf7bc2d8856d6971cea73b1d50c9c51d36971faf1abc169a0d5f85a382"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9503f79e12d5d80b3efd4d01312853565c05367493379df76d2674af881caa"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f449a50cc33f0384f633894d8d3cd020e3ccef81879c6e6245c3c375c448625"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82052be3e6d9e0c123499127782a01a2b224b8af8c62ab46b3f6197035ad94e9"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20063c7acf1eec550c8eb098deb5ed9e1bb0521613b03bb93644b810986027ac"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:489cced07a4c11488f47aab1f00d0c572506883f877af100a38f1fedaa884c3a"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea9b3bab329aeaa603ed3bf605f1e2a6f36496ad7e0e1aa42025f368ee2dc07b"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ca117819d8ad113413016cb29774b3f6d99ad23c220069789fc050267b786c16"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2dfb612dcbe70fb7cdcf3499e8d483079b89749c857a8f6e80263b021745c730"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9b615d3da0d60e7d53c62e22b4fd1c70f4ae5993a44687b011ea3a2e49051b8"}, + {file = "aiohttp-3.10.11-cp311-cp311-win32.whl", hash = "sha256:29103f9099b6068bbdf44d6a3d090e0a0b2be6d3c9f16a070dd9d0d910ec08f9"}, + {file = "aiohttp-3.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:236b28ceb79532da85d59aa9b9bf873b364e27a0acb2ceaba475dc61cffb6f3f"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4"}, + {file = "aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb"}, + {file = "aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:703938e22434d7d14ec22f9f310559331f455018389222eed132808cd8f44127"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bc50b63648840854e00084c2b43035a62e033cb9b06d8c22b409d56eb098413"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f0463bf8b0754bc744e1feb61590706823795041e63edf30118a6f0bf577461"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6c6dec398ac5a87cb3a407b068e1106b20ef001c344e34154616183fe684288"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcaf2d79104d53d4dcf934f7ce76d3d155302d07dae24dff6c9fffd217568067"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25fd5470922091b5a9aeeb7e75be609e16b4fba81cdeaf12981393fb240dd10e"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbde2ca67230923a42161b1f408c3992ae6e0be782dca0c44cb3206bf330dee1"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:249c8ff8d26a8b41a0f12f9df804e7c685ca35a207e2410adbd3e924217b9006"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878ca6a931ee8c486a8f7b432b65431d095c522cbeb34892bee5be97b3481d0f"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8663f7777ce775f0413324be0d96d9730959b2ca73d9b7e2c2c90539139cbdd6"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd3f10b01f0c31481fba8d302b61603a2acb37b9d30e1d14e0f5a58b7b18a31"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e8d8aad9402d3aa02fdc5ca2fe68bcb9fdfe1f77b40b10410a94c7f408b664d"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38e3c4f80196b4f6c3a85d134a534a56f52da9cb8d8e7af1b79a32eefee73a00"}, + {file = "aiohttp-3.10.11-cp313-cp313-win32.whl", hash = "sha256:fc31820cfc3b2863c6e95e14fcf815dc7afe52480b4dc03393c4873bb5599f71"}, + {file = "aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74baf1a7d948b3d640badeac333af581a367ab916b37e44cf90a0334157cdfd2"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:473aebc3b871646e1940c05268d451f2543a1d209f47035b594b9d4e91ce8339"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c2f746a6968c54ab2186574e15c3f14f3e7f67aef12b761e043b33b89c5b5f95"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d110cabad8360ffa0dec8f6ec60e43286e9d251e77db4763a87dcfe55b4adb92"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0099c7d5d7afff4202a0c670e5b723f7718810000b4abcbc96b064129e64bc7"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0316e624b754dbbf8c872b62fe6dcb395ef20c70e59890dfa0de9eafccd2849d"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5f7ab8baf13314e6b2485965cbacb94afff1e93466ac4d06a47a81c50f9cca"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c891011e76041e6508cbfc469dd1a8ea09bc24e87e4c204e05f150c4c455a5fa"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9208299251370ee815473270c52cd3f7069ee9ed348d941d574d1457d2c73e8b"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:459f0f32c8356e8125f45eeff0ecf2b1cb6db1551304972702f34cd9e6c44658"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:14cdc8c1810bbd4b4b9f142eeee23cda528ae4e57ea0923551a9af4820980e39"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:971aa438a29701d4b34e4943e91b5e984c3ae6ccbf80dd9efaffb01bd0b243a9"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9a309c5de392dfe0f32ee57fa43ed8fc6ddf9985425e84bd51ed66bb16bce3a7"}, + {file = "aiohttp-3.10.11-cp38-cp38-win32.whl", hash = "sha256:9ec1628180241d906a0840b38f162a3215114b14541f1a8711c368a8739a9be4"}, + {file = "aiohttp-3.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:9c6e0ffd52c929f985c7258f83185d17c76d4275ad22e90aa29f38e211aacbec"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc493a2e5d8dc79b2df5bec9558425bcd39aff59fc949810cbd0832e294b106"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3e70f24e7d0405be2348da9d5a7836936bf3a9b4fd210f8c37e8d48bc32eca6"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968b8fb2a5eee2770eda9c7b5581587ef9b96fbdf8dcabc6b446d35ccc69df01"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deef4362af9493d1382ef86732ee2e4cbc0d7c005947bd54ad1a9a16dd59298e"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:686b03196976e327412a1b094f4120778c7c4b9cff9bce8d2fdfeca386b89829"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bf6d027d9d1d34e1c2e1645f18a6498c98d634f8e373395221121f1c258ace8"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:099fd126bf960f96d34a760e747a629c27fb3634da5d05c7ef4d35ef4ea519fc"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73c4d3dae0b4644bc21e3de546530531d6cdc88659cdeb6579cd627d3c206aa"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c5580f3c51eea91559db3facd45d72e7ec970b04528b4709b1f9c2555bd6d0b"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf6429f0caabfd8a30c4e2eaecb547b3c340e4730ebfe25139779b9815ba138"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d97187de3c276263db3564bb9d9fad9e15b51ea10a371ffa5947a5ba93ad6777"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0acafb350cfb2eba70eb5d271f55e08bd4502ec35e964e18ad3e7d34d71f7261"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c13ed0c779911c7998a58e7848954bd4d63df3e3575f591e321b19a2aec8df9f"}, + {file = "aiohttp-3.10.11-cp39-cp39-win32.whl", hash = "sha256:22b7c540c55909140f63ab4f54ec2c20d2635c0289cdd8006da46f3327f971b9"}, + {file = "aiohttp-3.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:7b26b1551e481012575dab8e3727b16fe7dd27eb2711d2e63ced7368756268fb"}, + {file = "aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7"}, ] [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -2514,6 +2514,97 @@ files = [ [package.extras] twisted = ["twisted"] +[[package]] +name = "propcache" +version = "0.2.1" +description = "Accelerated property cache" +optional = true +python-versions = ">=3.9" +files = [ + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, +] + [[package]] name = "proto-plus" version = "1.24.0" @@ -3893,108 +3984,99 @@ files = [ [[package]] name = "yarl" -version = "1.11.1" +version = "1.18.3" description = "Yet another URL library" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00"}, - {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d"}, - {file = "yarl-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e"}, - {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc"}, - {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec"}, - {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf"}, - {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49"}, - {file = "yarl-1.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff"}, - {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad"}, - {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145"}, - {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd"}, - {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26"}, - {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46"}, - {file = "yarl-1.11.1-cp310-cp310-win32.whl", hash = "sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91"}, - {file = "yarl-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998"}, - {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68"}, - {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe"}, - {file = "yarl-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675"}, - {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63"}, - {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27"}, - {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5"}, - {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92"}, - {file = "yarl-1.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b"}, - {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a"}, - {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83"}, - {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff"}, - {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c"}, - {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e"}, - {file = "yarl-1.11.1-cp311-cp311-win32.whl", hash = "sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6"}, - {file = "yarl-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b"}, - {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0"}, - {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265"}, - {file = "yarl-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867"}, - {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd"}, - {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef"}, - {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8"}, - {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870"}, - {file = "yarl-1.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2"}, - {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84"}, - {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa"}, - {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff"}, - {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239"}, - {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45"}, - {file = "yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447"}, - {file = "yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639"}, - {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c"}, - {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e"}, - {file = "yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93"}, - {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d"}, - {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7"}, - {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089"}, - {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5"}, - {file = "yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5"}, - {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786"}, - {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318"}, - {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82"}, - {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a"}, - {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da"}, - {file = "yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979"}, - {file = "yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367"}, - {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dae7bd0daeb33aa3e79e72877d3d51052e8b19c9025ecf0374f542ea8ec120e4"}, - {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3ff6b1617aa39279fe18a76c8d165469c48b159931d9b48239065767ee455b2b"}, - {file = "yarl-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3257978c870728a52dcce8c2902bf01f6c53b65094b457bf87b2644ee6238ddc"}, - {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f351fa31234699d6084ff98283cb1e852270fe9e250a3b3bf7804eb493bd937"}, - {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8aef1b64da41d18026632d99a06b3fefe1d08e85dd81d849fa7c96301ed22f1b"}, - {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7175a87ab8f7fbde37160a15e58e138ba3b2b0e05492d7351314a250d61b1591"}, - {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba444bdd4caa2a94456ef67a2f383710928820dd0117aae6650a4d17029fa25e"}, - {file = "yarl-1.11.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ea9682124fc062e3d931c6911934a678cb28453f957ddccf51f568c2f2b5e05"}, - {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8418c053aeb236b20b0ab8fa6bacfc2feaaf7d4683dd96528610989c99723d5f"}, - {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:61a5f2c14d0a1adfdd82258f756b23a550c13ba4c86c84106be4c111a3a4e413"}, - {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f3a6d90cab0bdf07df8f176eae3a07127daafcf7457b997b2bf46776da2c7eb7"}, - {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:077da604852be488c9a05a524068cdae1e972b7dc02438161c32420fb4ec5e14"}, - {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:15439f3c5c72686b6c3ff235279630d08936ace67d0fe5c8d5bbc3ef06f5a420"}, - {file = "yarl-1.11.1-cp38-cp38-win32.whl", hash = "sha256:238a21849dd7554cb4d25a14ffbfa0ef380bb7ba201f45b144a14454a72ffa5a"}, - {file = "yarl-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:67459cf8cf31da0e2cbdb4b040507e535d25cfbb1604ca76396a3a66b8ba37a6"}, - {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:884eab2ce97cbaf89f264372eae58388862c33c4f551c15680dd80f53c89a269"}, - {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a336eaa7ee7e87cdece3cedb395c9657d227bfceb6781295cf56abcd3386a26"}, - {file = "yarl-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87f020d010ba80a247c4abc335fc13421037800ca20b42af5ae40e5fd75e7909"}, - {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:637c7ddb585a62d4469f843dac221f23eec3cbad31693b23abbc2c366ad41ff4"}, - {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48dfd117ab93f0129084577a07287376cc69c08138694396f305636e229caa1a"}, - {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e0ae31fb5ccab6eda09ba1494e87eb226dcbd2372dae96b87800e1dcc98804"}, - {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46f81501160c28d0c0b7333b4f7be8983dbbc161983b6fb814024d1b4952f79"}, - {file = "yarl-1.11.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04293941646647b3bfb1719d1d11ff1028e9c30199509a844da3c0f5919dc520"}, - {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:250e888fa62d73e721f3041e3a9abf427788a1934b426b45e1b92f62c1f68366"}, - {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e8f63904df26d1a66aabc141bfd258bf738b9bc7bc6bdef22713b4f5ef789a4c"}, - {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:aac44097d838dda26526cffb63bdd8737a2dbdf5f2c68efb72ad83aec6673c7e"}, - {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:267b24f891e74eccbdff42241c5fb4f974de2d6271dcc7d7e0c9ae1079a560d9"}, - {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6907daa4b9d7a688063ed098c472f96e8181733c525e03e866fb5db480a424df"}, - {file = "yarl-1.11.1-cp39-cp39-win32.whl", hash = "sha256:14438dfc5015661f75f85bc5adad0743678eefee266ff0c9a8e32969d5d69f74"}, - {file = "yarl-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:94d0caaa912bfcdc702a4204cd5e2bb01eb917fc4f5ea2315aa23962549561b0"}, - {file = "yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38"}, - {file = "yarl-1.11.1.tar.gz", hash = "sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [extras] logging = ["asgi-logger"] diff --git a/python/kserve/pyproject.toml b/python/kserve/pyproject.toml index c6ec0d2e075..b0f4e8412a5 100644 --- a/python/kserve/pyproject.toml +++ b/python/kserve/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" authors = [ "The KServe Authors ", diff --git a/python/kserve/test/conftest.py b/python/kserve/test/conftest.py new file mode 100644 index 00000000000..8e1975cb840 --- /dev/null +++ b/python/kserve/test/conftest.py @@ -0,0 +1,32 @@ +# Copyright 2024 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from kserve import ModelServer, ModelRepository +from kserve.protocol.rest.server import RESTServer +from kserve.model_server import app as kserve_app + + +@pytest.fixture(scope="session") +def server(): + server = ModelServer(registered_models=ModelRepository()) + rest_server = RESTServer( + kserve_app, + server.dataplane, + server.model_repository_extension, + http_port=8080, + ) + rest_server.create_application() + yield server + kserve_app.routes.clear() diff --git a/python/kserve/test/fixtures/openai/embedding.json b/python/kserve/test/fixtures/openai/embedding.json new file mode 100644 index 00000000000..e22b9217d64 --- /dev/null +++ b/python/kserve/test/fixtures/openai/embedding.json @@ -0,0 +1,400 @@ +{ + "data": [ + { + "index": 0, + "embedding": [ + 0.09812460094690323, + 0.06781269609928131, + 0.06252317875623703, + 0.09508483111858368, + 0.03664761036634445, + -0.003984640818089247, + 0.007477519102394581, + -0.013231460005044937, + 0.06288369745016098, + 0.02249549701809883, + 0.072695791721344, + -0.03127428889274597, + 0.04635513201355934, + -0.012554519809782505, + 0.04781476408243179, + -0.004910346586257219, + 0.04941992461681366, + -0.06410930305719376, + -0.09696582704782486, + 0.03288879990577698, + 0.05410446599125862, + 0.03532857075333595, + 0.0330505445599556, + 0.014699422754347324, + -0.03343060985207558, + -0.025615829974412918, + -0.050792112946510315, + 0.07325457781553268, + 0.11027400195598602, + -0.029661813750863075, + -0.06755708158016205, + -0.03057151474058628, + 0.039560236036777496, + 0.04547601938247681, + 0.015996191650629044, + 0.038550399243831635, + -0.010954048484563828, + 0.08483563363552094, + -0.04428705945611, + -0.006796404253691435, + 0.00942566804587841, + 0.000050668884796323255, + 0.0013035491574555635, + -0.011969789862632751, + 0.013645154424011707, + -0.08417423069477081, + -0.00016514321032445878, + 0.005483775865286589, + 0.025615083053708076, + -0.031545281410217285, + -0.10734470188617706, + -0.04578779265284538, + -0.09117487818002701, + -0.0025105553213506937, + 0.01799839362502098, + 0.049401599913835526, + 0.006184802390635014, + 0.059796303510665894, + 0.027002600952982903, + -0.016122261062264442, + -0.018149685114622116, + -0.02363482303917408, + -0.09489713609218597, + 0.06621629744768143, + 0.1492275595664978, + 0.024338779971003532, + 0.0012102446053177118, + 0.006072014570236206, + -0.09917040914297104, + 0.08505810797214508, + 0.0308261476457119, + 0.02918657846748829, + -0.02395595796406269, + -0.0105593865737319, + -0.07215200364589691, + -0.03525640070438385, + 0.033346593379974365, + -0.04392950236797333, + 0.11975520849227905, + 0.08864743262529373, + -0.09591902047395706, + -0.059080179780721664, + -0.008292674086987972, + 0.03816923126578331, + 0.04979965463280678, + -0.0326821506023407, + 0.019901003688573837, + -0.10837855935096741, + 0.014679051004350185, + 0.01811782829463482, + -0.06131783127784729, + -0.08975033462047577, + 0.04922163859009743, + -0.02087101712822914, + 0.004055131692439318, + -0.03543014079332352, + -0.05657777190208435, + -0.048313725739717484, + -0.024660276249051094, + 0.07359182834625244, + -0.020923534408211708, + 0.04069769009947777, + 0.032326482236385345, + 0.07668346911668777, + -0.014747701585292816, + -0.1030452772974968, + -0.04274492338299751, + -0.0662931501865387, + 0.015474040061235428, + -0.026800300925970078, + -0.09175194799900055, + -0.035600464791059494, + -0.018932482227683067, + -0.004029575269669294, + -0.020193425938487053, + -0.05853481963276863, + -0.10180167108774185, + -0.004487900994718075, + -0.06976304948329926, + 0.06024095416069031, + 0.029810858890414238, + 0.06380830705165863, + -0.06730612367391586, + 0.0033509465865790844, + -0.060039862990379333, + -0.09313665330410004, + 0.045675043016672134, + -6.719925045458755E-33, + 0.007433182094246149, + -0.06510976701974869, + -0.021259166300296783, + 0.035196054726839066, + 0.046336084604263306, + -0.07030496001243591, + -0.06128956750035286, + 0.017366604879498482, + -0.0074797123670578, + -0.01846875622868538, + 0.001607456593774259, + -0.02580185979604721, + 0.030047021806240082, + 0.00875167828053236, + 0.05092949420213699, + 0.07171623408794403, + -0.07271793484687805, + 0.1326150894165039, + -0.00803415384143591, + 0.03693223372101784, + -0.023691322654485703, + 0.024269403889775276, + -0.026396209374070168, + -0.018338508903980255, + -0.014753326773643494, + -0.07431734353303909, + 0.016344867646694183, + 0.01803700067102909, + -0.003123299218714237, + 0.04128265753388405, + 0.050598617643117905, + 0.04449482262134552, + -0.04755300655961037, + -0.002626477275043726, + 0.054667823016643524, + 0.046977970749139786, + 0.06379827111959457, + -0.02183675765991211, + 0.0011920140823349357, + 0.006154955364763737, + -0.010474730283021927, + -0.05154884234070778, + 0.021718978881835938, + -0.03787209838628769, + 0.0879114493727684, + 0.02365758642554283, + 0.019885694608092308, + 0.021743159741163254, + -0.06192107871174812, + 0.020616168156266212, + -0.010686979629099369, + 0.05776217207312584, + 0.059402864426374435, + -0.0288755651563406, + 0.06947711855173111, + 0.001013647997751832, + 0.042007993906736374, + 0.034752000123262405, + -0.0016647797310724854, + -0.010128127411007881, + -0.054719988256692886, + 0.04056468978524208, + -0.056016407907009125, + 0.057263199239969254, + -0.025760957971215248, + 0.029396990314126015, + 0.010298472829163074, + -0.04915247857570648, + 0.015427723526954651, + 0.02869337983429432, + 0.011681458912789822, + -0.006968752946704626, + -0.08346767723560333, + 0.10836982727050781, + -0.04198267310857773, + -0.04266303777694702, + -0.021897369995713234, + -0.021625958383083344, + -0.007852158509194851, + 0.03822033107280731, + -0.01800902746617794, + -0.14943544566631317, + 0.023226428776979446, + 0.015028486028313637, + -0.03989404812455177, + 0.0037516923621296883, + 0.043006666004657745, + -0.08475463092327118, + -0.03029675781726837, + -0.02013072930276394, + -0.025030167773365974, + 0.003526018001139164, + 0.0582348108291626, + 0.00549469655379653, + 0.006489734165370464, + 3.174682205178722E-33, + -0.04243830591440201, + 0.02992221526801586, + -0.08836192637681961, + 0.06575305014848709, + 0.10463074594736099, + -0.008896679617464542, + 0.042894456535577774, + -0.09550556540489197, + 0.03168181702494621, + 0.07352744787931442, + -0.13084876537322998, + 0.025529906153678894, + 0.016062166541814804, + -0.0043756430968642235, + 0.029202574864029884, + -0.008134165778756142, + 0.06525744497776031, + 0.0006216196925379336, + -0.00783581379801035, + 0.04156062752008438, + -0.04372049495577812, + 0.09504026919603348, + -0.025842653587460518, + 0.08701659739017487, + -0.04147154465317726, + 0.03544049710035324, + -0.014387118630111217, + -0.026075217872858047, + -0.09590037912130356, + -0.008881507441401482, + 0.007069987244904041, + -0.09052383154630661, + -0.0797419473528862, + -0.014227607287466526, + -0.05348994582891464, + 0.05122567340731621, + 0.024540821090340614, + -0.03697463870048523, + -0.07341103255748749, + -0.006874367594718933, + 0.0068125249817967415, + -0.0329182967543602, + 0.015790680423378944, + 0.1059456467628479, + 0.022715147584676743, + -0.05641724914312363, + -0.03206418454647064, + -0.10509151220321655, + -0.032904643565416336, + 0.0513918362557888, + -0.10034642368555069, + 0.04499524086713791, + -0.03296136111021042, + -0.019640814512968063, + -0.10540889203548431, + 0.011973707005381584, + -0.011170891113579273, + -0.06957735121250153, + -0.009789666160941124, + 0.016010869294404984, + -0.05117956921458244, + 0.008791363798081875, + -0.006576142739504576, + 0.06629248708486557, + 0.10956112295389175, + -0.05475931614637375, + -0.05709327384829521, + 0.050297729671001434, + 0.01262251753360033, + 0.02845410816371441, + 0.1343768984079361, + 0.011013655923306942, + -0.1519516557455063, + -0.049476105719804764, + -0.06537330895662308, + -0.06709235161542892, + -0.06969746947288513, + -0.03129567205905914, + -0.061766088008880615, + -0.0742039680480957, + 0.02897379919886589, + -0.008312447927892208, + 0.04321928694844246, + -0.017557401210069656, + -0.005178697872906923, + -0.05432431399822235, + -0.04127553850412369, + -0.08270692080259323, + -0.015986543148756027, + 0.008618013933300972, + 0.0006255805492401123, + -0.06523493677377701, + 0.07926347851753235, + 0.026802241802215576, + -0.025414051488041878, + -1.965175222551352E-8, + -0.022532736882567406, + -0.015100589022040367, + 0.08194082230329514, + -0.03959040343761444, + 0.04711084067821503, + 0.015206287615001202, + 0.06537682563066483, + 0.018435340374708176, + -0.007971749641001225, + -0.03773093223571777, + 0.023044027388095856, + 0.040450308471918106, + -0.05697207897901535, + -0.003070066450163722, + 0.05366634577512741, + 0.06094937399029732, + 0.0383155420422554, + -0.03807567432522774, + -0.02675454691052437, + 0.0674038827419281, + -0.05417702719569206, + 0.04589824378490448, + -0.012908662669360638, + 0.015068446286022663, + 0.03300931304693222, + 0.004980806726962328, + 0.0434085987508297, + 0.06518961489200592, + 0.016215743497014046, + 0.03613708168268204, + 0.05567425861954689, + 0.11904114484786987, + 0.024056648835539818, + 0.015141750685870647, + 0.060563839972019196, + 0.03681957721710205, + 0.041256338357925415, + -0.03155893832445145, + 0.05625439062714577, + -0.025755975395441055, + 0.013329358771443367, + 0.04844075068831444, + -0.021774696186184883, + 0.11008109897375107, + 0.03858953341841698, + 0.03805913031101227, + -0.004871034529060125, + -0.04328330606222153, + -0.02537413313984871, + 0.016013741493225098, + 0.018330948427319527, + 0.05638059601187706, + 0.03461501747369766, + -0.020659904927015305, + 0.02127760276198387, + 0.01893790438771248, + 0.03383444622159004, + -0.0069625237956643105, + -0.024325989186763763, + -0.019780240952968597, + -0.01989535242319107, + 0.034644052386283875, + 0.049627240747213364, + -0.029213014990091324 + ], + "object": "embedding" + } + ], + "model": "hf-text-embedding-openai", + "object": "list", + "usage": { + "prompt_tokens": 8, + "total_tokens": 8 + } +} diff --git a/python/kserve/test/fixtures/openai/embedding_create_params.json b/python/kserve/test/fixtures/openai/embedding_create_params.json new file mode 100644 index 00000000000..4eb7fb177bb --- /dev/null +++ b/python/kserve/test/fixtures/openai/embedding_create_params.json @@ -0,0 +1,5 @@ +{ + "input": "This is an example sentence.", + "model": "hf-text-embedding-openai", + "encoding_format": "float" +} diff --git a/python/kserve/test/test_dataplane.py b/python/kserve/test/test_dataplane.py index 2f7e5409958..9243f725c88 100644 --- a/python/kserve/test/test_dataplane.py +++ b/python/kserve/test/test_dataplane.py @@ -36,7 +36,7 @@ from kserve.errors import InvalidInput, ModelNotFound from kserve.model import PredictorProtocol, PredictorConfig from kserve.protocol.dataplane import DataPlane -from kserve.protocol.rest.openai import CompletionRequest, OpenAIModel +from kserve.protocol.rest.openai import CompletionRequest, OpenAICompletionModel from kserve.model_repository import ModelRepository from kserve.ray import RayModel from test.test_server import ( @@ -423,7 +423,7 @@ async def test_infer_ce_avro_binary(self, dataplane_with_ce_model): class TestDataPlaneOpenAI: MODEL_NAME = "TestModel" - class DummyOpenAIModel(OpenAIModel): + class DummyOpenAIModel(OpenAICompletionModel): async def create_completion( self, params: CompletionRequest ) -> Union[Completion, AsyncIterator[Completion]]: @@ -434,7 +434,7 @@ async def create_chat_completion( ) -> Union[ChatCompletion, AsyncIterator[ChatCompletionChunk]]: pass - async def test_infer_on_openai_model_raises(self): + async def test_infer_on_openai_completion_model_raises(self): openai_model = self.DummyOpenAIModel(self.MODEL_NAME) repo = ModelRepository() repo.update(openai_model) @@ -448,16 +448,13 @@ async def test_infer_on_openai_model_raises(self): assert ( exc.value.reason - == "Model TestModel is of type OpenAIModel. It does not support the infer method." + == "Model TestModel is of type OpenAICompletionModel. It does not support the infer method." ) @pytest.mark.asyncio class TestDataplaneTransformer: - @pytest.mark.skip( - "pytest_httpx requires python >= 3.9. It can be enabled once we remove the support for python 3.8" - ) async def test_dataplane_rest_with_ssl_enabled(self, httpx_mock): # scenario: getting a 2xx response from predictor with ssl enabled predictor_host = "ready.host" @@ -499,9 +496,6 @@ async def test_dataplane_grpc_with_ssl_enabled(self, mock_grpc_client): url=predictor_host, timeout=5, retries=2, use_ssl=True ) - @pytest.mark.skip( - "pytest_httpx requires python >= 3.9. It can be enabled once we remove the support for python 3.8" - ) async def test_server_readiness_v1(self, httpx_mock): # scenario: getting a 2xx response from predictor predictor_host = "ready.host" @@ -538,9 +532,6 @@ async def test_server_readiness_v1(self, httpx_mock): with pytest.raises(httpx.HTTPStatusError): await dataplane.ready() - @pytest.mark.skip( - "pytest_httpx requires python >= 3.9. It can be enabled once we remove the support for python 3.8" - ) async def test_server_readiness_v2(self, httpx_mock): # scenario: getting a 2xx response from predictor predictor_host = "ready.host" @@ -634,9 +625,6 @@ async def test_server_readiness_grpc_v2(self, mock_grpc_client): url=predictor_host, timeout=5, retries=2, use_ssl=False ) - @pytest.mark.skip( - "pytest_httpx requires python >= 3.9. It can be enabled once we remove the support for python 3.8" - ) async def test_model_readiness_v1(self, httpx_mock): # scenario: getting a 2xx response from predictor predictor_host = "ready.host" @@ -698,9 +686,6 @@ async def test_model_readiness_v1(self, httpx_mock): dataplane._model_registry.update(not_ready_model) assert await dataplane.model_ready(not_ready_model.name) is False - @pytest.mark.skip( - "pytest_httpx requires python >= 3.9. It can be enabled once we remove the support for python 3.8" - ) async def test_model_readiness_v2(self, httpx_mock): # scenario: getting a 2xx response from predictor predictor_host = "ready.host" diff --git a/python/kserve/test/test_inference_client.py b/python/kserve/test/test_inference_client.py index 50eca5197f3..69d145463da 100644 --- a/python/kserve/test/test_inference_client.py +++ b/python/kserve/test/test_inference_client.py @@ -19,12 +19,11 @@ import pytest import pytest_asyncio -from kserve import ModelServer, InferenceRESTClient, InferRequest, InferInput +from kserve import InferenceRESTClient, InferRequest, InferInput from kserve.model_server import app as kserve_app from kserve.errors import UnsupportedProtocol from kserve.inference_client import RESTConfig from kserve.protocol.infer_type import RequestedOutput -from kserve.protocol.rest.server import RESTServer from test.test_server import DummyModel @@ -32,12 +31,7 @@ class TestInferenceRESTClient: @pytest_asyncio.fixture(scope="class") - async def app(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() + async def app(self, server): model = DummyModel("TestModel") model.load() not_ready_model = DummyModel("NotReadyModel") @@ -47,7 +41,6 @@ async def app(self): yield kserve_app await server.model_repository_extension.unload("TestModel") await server.model_repository_extension.unload("NotReadyModel") - kserve_app.routes.clear() @pytest_asyncio.fixture(scope="class") async def rest_client(self, request, app): diff --git a/python/kserve/test/test_inference_client_factory.py b/python/kserve/test/test_inference_client_factory.py new file mode 100644 index 00000000000..bcfdf374c18 --- /dev/null +++ b/python/kserve/test/test_inference_client_factory.py @@ -0,0 +1,60 @@ +# Copyright 2024 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from kserve.utils.inference_client_factory import InferenceClientFactory +from kserve.inference_client import InferenceRESTClient, RESTConfig + + +@pytest.fixture +def factory(): + return InferenceClientFactory() + + +def test_get_rest_client_v1(factory): + config = RESTConfig(protocol="v1") + client = factory.get_rest_client(config) + assert client._config.protocol == "v1" + assert factory._rest_v1_client is client + + +def test_get_rest_cleint_v1_config_none(factory): + client = factory.get_rest_client() + assert isinstance(client, InferenceRESTClient) + assert client._config.protocol == "v1" + assert factory._rest_v1_client is client + + +def test_get_rest_client_v2(factory): + config = RESTConfig(protocol="v2") + client = factory.get_rest_client(config) + assert isinstance(client, InferenceRESTClient) + assert client._config.protocol == "v2" + assert factory._rest_v2_client is client + + +def test_get_rest_client_v1_cached(factory): + config = RESTConfig(protocol="v1") + client1 = factory.get_rest_client(config) + client2 = factory.get_rest_client(config) + assert client1._config.protocol == "v1" + assert client1 is client2 + + +def test_get_rest_client_v2_cached(factory): + config = RESTConfig(protocol="v2") + client1 = factory.get_rest_client(config) + client2 = factory.get_rest_client(config) + assert client1._config.protocol == "v2" + assert client1 is client2 diff --git a/python/kserve/test/test_model_repository.py b/python/kserve/test/test_model_repository.py index 20197058cda..306db097d70 100644 --- a/python/kserve/test/test_model_repository.py +++ b/python/kserve/test/test_model_repository.py @@ -14,17 +14,23 @@ import pytest from kserve import ModelRepository, Model -from kserve.protocol.rest.openai import CompletionRequest, OpenAIModel +from kserve.protocol.rest.openai import ( + CompletionRequest, + OpenAICompletionModel, + EmbeddingRequest, + OpenAIEmbeddingModel, +) from unittest.mock import patch from kserve.protocol.rest.openai.types.openapi import ( CreateChatCompletionResponse as ChatCompletion, CreateChatCompletionStreamResponse as ChatCompletionChunk, CreateCompletionResponse as Completion, + Embedding, ) from typing import AsyncIterator, Union -class DummyOpenAIModel(OpenAIModel): +class DummyOpenAICompletionModel(OpenAICompletionModel): async def create_completion( self, params: CompletionRequest ) -> Union[Completion, AsyncIterator[Completion]]: @@ -36,6 +42,11 @@ async def create_chat_completion( pass +class DummyOpenAIEmbeddingModel(OpenAIEmbeddingModel): + async def create_embedding(self, params: EmbeddingRequest) -> Embedding: + pass + + def test_adding_kserve_model(): repo = ModelRepository() repo.update(Model(name="kserve-model")) @@ -47,15 +58,26 @@ def test_adding_kserve_model(): assert actual.name == "kserve-model" -def test_adding_openai_model(): +def test_adding_openai_completion_model(): + repo = ModelRepository() + repo.update(DummyOpenAICompletionModel(name="openai-completion-model")) + + actual = repo.get_model("openai-completion-model") + + assert actual is not None + assert isinstance(actual, OpenAICompletionModel) + assert actual.name == "openai-completion-model" + + +def test_adding_openai_embedding_model(): repo = ModelRepository() - repo.update(DummyOpenAIModel(name="openai-model")) + repo.update(DummyOpenAIEmbeddingModel(name="openai-embedding-model")) - actual = repo.get_model("openai-model") + actual = repo.get_model("openai-embedding-model") assert actual is not None - assert isinstance(actual, OpenAIModel) - assert actual.name == "openai-model" + assert isinstance(actual, OpenAIEmbeddingModel) + assert actual.name == "openai-embedding-model" @pytest.mark.asyncio @@ -83,7 +105,7 @@ async def test_is_model_ready_kserve_model(): @pytest.mark.asyncio async def test_is_model_ready_openai_model(): repo = ModelRepository() - model = DummyOpenAIModel(name="openai-model") + model = DummyOpenAICompletionModel(name="openai-model") repo.update(model) actual = await repo.is_model_ready("openai-model") diff --git a/python/kserve/test/test_openai.py b/python/kserve/test/test_openai_completion.py similarity index 100% rename from python/kserve/test/test_openai.py rename to python/kserve/test/test_openai_completion.py diff --git a/python/kserve/test/test_openai_embedding.py b/python/kserve/test/test_openai_embedding.py new file mode 100644 index 00000000000..44cb813da0d --- /dev/null +++ b/python/kserve/test/test_openai_embedding.py @@ -0,0 +1,73 @@ +# Copyright 2025 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from pathlib import Path +from typing import Tuple + +import pytest + +from kserve.protocol.rest.openai import ( + EmbeddingRequest, + OpenAIEmbeddingModel, +) +from kserve.protocol.rest.openai.types.openapi import ( + CreateEmbeddingRequest, +) +from kserve.protocol.rest.openai.types.openapi import ( + CreateEmbeddingResponse as Embedding, +) + +FIXTURES_PATH = Path(__file__).parent / "fixtures" / "openai" + + +class DummyModel(OpenAIEmbeddingModel): + data: Tuple[Embedding] + + def __init__(self, data: Tuple[Embedding]): + super().__init__("dummy-model") + self.data = data + + async def create_embedding(self, request: EmbeddingRequest) -> Embedding: + return self.data[0] + + +@pytest.fixture +def embedding(): + with open(FIXTURES_PATH / "embedding.json") as f: + return Embedding.model_validate_json(f.read()) + + +@pytest.fixture +def embedding_create_params(): + with open(FIXTURES_PATH / "embedding_create_params.json") as f: + return CreateEmbeddingRequest.model_validate_json(f.read()) + + +@pytest.fixture +def dummy_model(embedding): + return DummyModel((embedding,)) + + +class TestOpenAICreateEmbedding: + @pytest.mark.asyncio + async def test_create_embedding( + self, + dummy_model: DummyModel, + embedding: Embedding, + embedding_create_params: CreateEmbeddingRequest, + ): + request = EmbeddingRequest(params=embedding_create_params) + c = await dummy_model.create_embedding(request) + assert isinstance(c, Embedding) + assert c.model_dump_json(indent=2) == embedding.model_dump_json(indent=2) diff --git a/python/kserve/test/test_server.py b/python/kserve/test/test_server.py index c0b2b67286c..76b0c9806ec 100644 --- a/python/kserve/test/test_server.py +++ b/python/kserve/test/test_server.py @@ -46,7 +46,6 @@ InferResponse, RequestedOutput, ) -from kserve.protocol.rest.server import RESTServer from kserve.protocol.rest.v2_datamodels import is_pydantic_2 from kserve.utils.utils import generate_uuid, get_predict_input, get_predict_response @@ -109,15 +108,6 @@ async def predict(self, request, headers=None): class TestStreamPredict: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() @pytest_asyncio.fixture(scope="class") async def app(self, server): # pylint: disable=no-self-use @@ -372,6 +362,11 @@ async def explain(self, payload, headers=None): return {"predictions": [datetime.datetime.now(tz=datetime.timezone.utc)]} +@pytest.fixture(scope="module") +def http_server_client(): + return TestClient(kserve_app, headers={"content-type": "application/json"}) + + @pytest.mark.asyncio class TestModel: async def test_validate(self): @@ -398,17 +393,7 @@ async def test_validate(self): class TestV1Endpoints: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer(registered_models=ModelRepository()) - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): model = DummyModel("TestModel") model.load() @@ -420,10 +405,6 @@ async def app(self, server): await server.model_repository_extension.unload("TestModel") await server.model_repository_extension.unload("DateTimeModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app, headers={"content-type": "application/json"}) - def test_liveness_v1(self, http_server_client): resp = http_server_client.get("/") assert resp.status_code == 200 @@ -484,17 +465,8 @@ def test_datetime_output_v1(self, http_server_client): class TestV2Endpoints: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): model = DummyModel("TestModel") model.load() @@ -514,10 +486,6 @@ async def app(self, server): await server.model_repository_extension.unload("FP16OutputModel") await server.model_repository_extension.unload("DateTimeModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app, headers={"content-type": "application/json"}) - def test_list_models_v2(self, http_server_client): resp = http_server_client.get("/v2/models") assert resp.status_code == 200 @@ -883,17 +851,8 @@ def test_datetime_output(self, http_server_client): class TestRayServer: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): # pylint: disable=no-self-use serve.start(http_options={"host": "0.0.0.0", "port": 9071}) @@ -909,10 +868,6 @@ async def app(self, server): # pylint: disable=no-self-use await server.model_repository_extension.unload("TestModel") serve.shutdown() - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app, headers={"content-type": "application/json"}) - def test_liveness_handler(self, http_server_client): resp = http_server_client.get("/") assert resp.status_code == 200 @@ -962,44 +917,22 @@ def test_explain(self, http_server_client): class TestTFHttpServerModelNotLoaded: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): # pylint: disable=no-self-use model = DummyModel("TestModel") server.register_model(model) yield kserve_app await server.model_repository_extension.unload("TestModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) - def test_model_not_ready_error(self, http_server_client): resp = http_server_client.get("/v1/models/TestModel") assert resp.status_code == 503 class TestTFHttpServerCloudEvent: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): # pylint: disable=no-self-use model = DummyCEModel("TestModel") model.load() @@ -1007,10 +940,6 @@ async def app(self, server): # pylint: disable=no-self-use yield kserve_app await server.model_repository_extension.unload("TestModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) - def test_predict_ce_structured(self, http_server_client): event = dummy_cloud_event({"instances": [[1, 2]]}) headers, body = to_structured(event) @@ -1165,17 +1094,8 @@ def test_predict_ce_bytes_bad_hex_format_exception(self, http_server_client): class TestTFHttpServerAvroCloudEvent: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): # pylint: disable=no-self-use model = DummyAvroCEModel("TestModel") model.load() @@ -1183,10 +1103,6 @@ async def app(self, server): # pylint: disable=no-self-use yield kserve_app await server.model_repository_extension.unload("TestModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) - def test_predict_ce_avro_binary(self, http_server_client): schema = avro.schema.parse(test_avsc_schema) msg = {"name": "foo", "favorite_number": 1, "favorite_color": "pink"} @@ -1217,21 +1133,16 @@ def test_predict_ce_avro_binary(self, http_server_client): class TestTFHttpServerLoadAndUnLoad: - @pytest.fixture(scope="class") - def app(self): - server = ModelServer( - registered_models=DummyModelRepository(test_load_success=True) - ) - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension + @pytest_asyncio.fixture(scope="class", autouse=True) + def app(self, server): + mp = pytest.MonkeyPatch() + mp.setattr( + server.model_repository_extension, + "_model_registry", + DummyModelRepository(test_load_success=True), ) - rest_server.create_application() - yield kserve_app - kserve_app.routes.clear() - - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) + yield + mp.undo() def test_load(self, http_server_client): resp = http_server_client.post("/v2/repository/models/model/load", content=b"") @@ -1247,21 +1158,16 @@ def test_unload(self, http_server_client): class TestTFHttpServerLoadAndUnLoadFailure: - @pytest.fixture(scope="class") - def app(self): - server = ModelServer( - registered_models=DummyModelRepository(test_load_success=False) - ) - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension + @pytest.fixture(scope="class", autouse=True) + def app(self, server): + mp = pytest.MonkeyPatch() + mp.setattr( + server.model_repository_extension, + "_model_registry", + DummyModelRepository(test_load_success=False), ) - rest_server.create_application() - yield kserve_app - kserve_app.routes.clear() - - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) + yield + mp.undo() def test_load_fail(self, http_server_client): resp = http_server_client.post("/v2/repository/models/model/load", content=b"") @@ -1275,27 +1181,14 @@ def test_unload_fail(self, http_server_client): class TestTFHttpServerModelNotReady: - @pytest.fixture(scope="class") - def server(self): - server = ModelServer() - rest_server = RESTServer( - kserve_app, server.dataplane, server.model_repository_extension - ) - rest_server.create_application() - yield server - kserve_app.routes.clear() - @pytest_asyncio.fixture(scope="class") + @pytest_asyncio.fixture(scope="class", autouse=True) async def app(self, server): # pylint: disable=no-self-use model = DummyModel("TestModel") server.register_model(model) yield kserve_app await server.model_repository_extension.unload("TestModel") - @pytest.fixture(scope="class") - def http_server_client(self, app): - return TestClient(app) - def test_model_not_ready_v1(self, http_server_client): resp = http_server_client.get("/v1/models/TestModel") assert resp.status_code == 503 diff --git a/python/kserve/test/test_v1beta1_inference_services_config.py b/python/kserve/test/test_v1beta1_inference_services_config.py index 27823906375..6cdfefa56d8 100644 --- a/python/kserve/test/test_v1beta1_inference_services_config.py +++ b/python/kserve/test/test_v1beta1_inference_services_config.py @@ -59,6 +59,10 @@ def make_instance(self, include_optional): image="0", ), ), + resource=kserve.models.v1beta1_resource_config.V1beta1ResourceConfig( + cpu_limit="", + memory_limit="", + ), ) else: return V1beta1InferenceServicesConfig( @@ -68,6 +72,10 @@ def make_instance(self, include_optional): image="0", ), ), + resource=kserve.models.v1beta1_resource_config.V1beta1ResourceConfig( + cpu_limit="", + memory_limit="", + ), ) def testV1beta1InferenceServicesConfig(self): diff --git a/python/kserve/test/test_v1beta1_resource_config.py b/python/kserve/test/test_v1beta1_resource_config.py new file mode 100644 index 00000000000..d6073899b05 --- /dev/null +++ b/python/kserve/test/test_v1beta1_resource_config.py @@ -0,0 +1,67 @@ +# Copyright 2023 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# coding: utf-8 + +""" + KServe + + Python SDK for KServe # noqa: E501 + + The version of the OpenAPI document: v0.1 + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest +import datetime + +import kserve +from kserve.models.v1beta1_resource_config import V1beta1ResourceConfig # noqa: E501 +from kserve.rest import ApiException + + +class TestV1beta1ResourceConfig(unittest.TestCase): + """V1beta1ResourceConfig unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional): + """Test V1beta1ResourceConfig + include_option is a boolean, when False only required + params are included, when True both required and + optional params are included""" + # model = kserve.models.v1beta1_resource_config.V1beta1ResourceConfig() # noqa: E501 + if include_optional: + return V1beta1ResourceConfig(cpu_limit="", memory_limit="") + else: + return V1beta1ResourceConfig( + cpu_limit="", + memory_limit="", + ) + + def testV1beta1ResourceConfig(self): + """Test V1beta1ResourceConfig""" + inst_req_only = self.make_instance(include_optional=False) + inst_req_and_optional = self.make_instance(include_optional=True) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/lgbserver/poetry.lock b/python/lgbserver/poetry.lock index 69bcb4acf9e..18411aaf853 100644 --- a/python/lgbserver/poetry.lock +++ b/python/lgbserver/poetry.lock @@ -1220,7 +1220,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/lgbserver/pyproject.toml b/python/lgbserver/pyproject.toml index c9bc11452d0..a8fd43f086f 100644 --- a/python/lgbserver/pyproject.toml +++ b/python/lgbserver/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "lgbserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for LightGBM. Not intended for use outside KServe Frameworks Images." authors = ["Lin Yiming "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/paddleserver/poetry.lock b/python/paddleserver/poetry.lock index aa3fd5a7ad0..f73a7f0c691 100644 --- a/python/paddleserver/poetry.lock +++ b/python/paddleserver/poetry.lock @@ -1231,7 +1231,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/paddleserver/pyproject.toml b/python/paddleserver/pyproject.toml index 5e0bd3da89f..1c189e6c66f 100644 --- a/python/paddleserver/pyproject.toml +++ b/python/paddleserver/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "paddleserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for Paddle. Not intended for use outside KServe Frameworks Images" authors = ["Zhengyuan Zhang "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/pmmlserver/poetry.lock b/python/pmmlserver/poetry.lock index 3c5f9a0bb56..db3fbe0e676 100644 --- a/python/pmmlserver/poetry.lock +++ b/python/pmmlserver/poetry.lock @@ -1264,7 +1264,7 @@ tests = ["pytest"] [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/pmmlserver/pyproject.toml b/python/pmmlserver/pyproject.toml index aecf1449bfe..d429316aaee 100644 --- a/python/pmmlserver/pyproject.toml +++ b/python/pmmlserver/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pmmlserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for PMML. Not intended for use outside KServe Frameworks Images." authors = ["AnyISalIn "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/sklearnserver/poetry.lock b/python/sklearnserver/poetry.lock index 8efe43d4d84..328b0f3844a 100644 --- a/python/sklearnserver/poetry.lock +++ b/python/sklearnserver/poetry.lock @@ -1220,7 +1220,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/sklearnserver/pyproject.toml b/python/sklearnserver/pyproject.toml index 0672b629b0c..830eab99771 100644 --- a/python/sklearnserver/pyproject.toml +++ b/python/sklearnserver/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "sklearnserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for scikit-learn. Not intended for use outside KServe Frameworks Images." authors = ["singhan "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/test_resources/graph/error_404_isvc/poetry.lock b/python/test_resources/graph/error_404_isvc/poetry.lock index 333ecf262d8..b8b52f60ab4 100644 --- a/python/test_resources/graph/error_404_isvc/poetry.lock +++ b/python/test_resources/graph/error_404_isvc/poetry.lock @@ -507,7 +507,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/test_resources/graph/error_404_isvc/pyproject.toml b/python/test_resources/graph/error_404_isvc/pyproject.toml index fb2ca85af64..e523f0e8285 100644 --- a/python/test_resources/graph/error_404_isvc/pyproject.toml +++ b/python/test_resources/graph/error_404_isvc/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "error_404_isvc" -version = "0.14.0" +version = "0.15.0rc0" description = "Custom isvc that always returns 404 with a JSON message" authors = ["The KServe Authors"] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/test_resources/graph/success_200_isvc/poetry.lock b/python/test_resources/graph/success_200_isvc/poetry.lock index 333ecf262d8..b8b52f60ab4 100644 --- a/python/test_resources/graph/success_200_isvc/poetry.lock +++ b/python/test_resources/graph/success_200_isvc/poetry.lock @@ -507,7 +507,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/test_resources/graph/success_200_isvc/pyproject.toml b/python/test_resources/graph/success_200_isvc/pyproject.toml index b539fa7c6b9..51f70223d2a 100644 --- a/python/test_resources/graph/success_200_isvc/pyproject.toml +++ b/python/test_resources/graph/success_200_isvc/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "success_200_isvc" -version = "0.14.0" +version = "0.15.0rc0" description = "Custom isvc that always returns 200 with a JSON SUCCESS message" authors = ["The KServe Authors"] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/python/xgbserver/poetry.lock b/python/xgbserver/poetry.lock index 98e53ddfe0e..36988e268f8 100644 --- a/python/xgbserver/poetry.lock +++ b/python/xgbserver/poetry.lock @@ -1220,7 +1220,7 @@ files = [ [[package]] name = "kserve" -version = "0.14.0" +version = "0.15.0rc0" description = "KServe Python SDK" optional = false python-versions = ">=3.9,<3.13" diff --git a/python/xgbserver/pyproject.toml b/python/xgbserver/pyproject.toml index 47a58643846..bb176294dae 100644 --- a/python/xgbserver/pyproject.toml +++ b/python/xgbserver/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "xgbserver" -version = "0.14.0" +version = "0.15.0rc0" description = "Model Server implementation for XGBoost. Not intended for use outside KServe Frameworks Images." authors = ["Ellis Tarn "] license = "https://github.com/kserve/kserve/blob/master/LICENSE" diff --git a/qpext/go.mod b/qpext/go.mod index 206752fa8e8..ae616fb7a5a 100644 --- a/qpext/go.mod +++ b/qpext/go.mod @@ -57,10 +57,10 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.6.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.195.0 // indirect @@ -82,3 +82,6 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +// Fixes CVE-2024-45338 +replace golang.org/x/net => golang.org/x/net v0.33.0 diff --git a/qpext/go.sum b/qpext/go.sum index 98173ccffb1..1587e571039 100644 --- a/qpext/go.sum +++ b/qpext/go.sum @@ -1,4 +1,3 @@ -cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -14,17 +13,12 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= -cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk= -cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -43,89 +37,41 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9 contrib.go.opencensus.io/exporter/zipkin v0.1.2 h1:YqE293IZrKtqPnpwDPH/lOqTWD/s3Iwabycam74JV3g= contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= -github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.11/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/IBM/sarama v1.43.1/go.mod h1:GG5q1RURtDNPz8xxJs3mgX6Ytak8Z9eLhAkJPObe2xE= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/ahmetb/gen-crd-api-reference-docs v0.3.1-0.20210609063737-0067dc6dcea2/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8= -github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= -github.com/aws/aws-sdk-go-v2/config v1.17.8/go.mod h1:UkCI3kb0sCdvtjiXYiU4Zx5h07BOpgBTtkPu/49r+kA= -github.com/aws/aws-sdk-go-v2/credentials v1.12.21/go.mod h1:O+4XyAt4e+oBAoIwNUYkRg3CVMscaIJdmZBOcPgJ8D8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17/go.mod h1:yIkQcCDYNsZfXpd5UX2Cy+sWA1jPgIhGTw9cOBzfVnQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.18/go.mod h1:DQtDYmexqR+z+B6HBCvY7zK/tuXKv6Zy/IwOXOK3eow= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.17/go.mod h1:r1Vuka0kyzqN0sZm4lYTXf0Vhl+o/mTLq6vKpBBZYaQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.23/go.mod h1:/w0eg9IhFGjGyyncHIQrXtU8wvNsTJOP0R6PPj0wf80= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6/go.mod h1:csZuQY65DAdFBt1oIjO5hhBR49kQqop4+lcuCjf2arA= -github.com/aws/aws-sdk-go-v2/service/sts v1.16.19/go.mod h1:h4J3oPZQbxLhzGnk+j9dfYHi5qIOVJ5kczZd658/ydM= -github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20221004211355-a250ad2ca1e3/go.mod h1:m06KtrZgOloUaePAQMv+Ha8kRmTnKdozTHZrweepIrw= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cert-manager/cert-manager v1.13.3/go.mod h1:BM2+Pt/NmSv1Zr25/MHv6BgIEF9IUxA1xAjp80qkxgc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chrismellard/docker-credential-acr-env v0.0.0-20221002210726-e883f69e0206/go.mod h1:1UmFRnmMnVsHwD+ZntmLkoVBB1ZLa6V+XXEbF6hZCxU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= -github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v25.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-resiliency v1.6.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -133,14 +79,11 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155/go.mod h1:5Wkq+JduFtdAXihLmeTJf+tRYIT4KBc2vPXDhwVo1pA= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= @@ -162,7 +105,6 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -170,17 +112,12 @@ github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDsl github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -212,10 +149,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -234,8 +169,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= -github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230209165335-3624968304fd/go.mod h1:x5fIlj5elU+/eYF60q4eASMQ9kDc+GMFa7UU9M3mFFw= -github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230209165335-3624968304fd/go.mod h1:6pjZpt+0dg+Z0kUEn53qLtD57raiZo/bqWzsuX6dDjo= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -248,21 +181,16 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= @@ -271,7 +199,6 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= @@ -280,17 +207,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb-client-go/v2 v2.9.0/go.mod h1:x7Jo5UHHl+w8wu8UnGiNobDDHygojXwJX4mx7rXGKMk= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -325,9 +241,6 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -335,32 +248,24 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -389,7 +294,6 @@ github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJ github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= -github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -401,20 +305,14 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/prometheus/statsd_exporter v0.27.1 h1:tcRJOmwlA83HPfWzosAgr2+zEN5XDFv+M2mn/uYkn5Y= github.com/prometheus/statsd_exporter v0.27.1/go.mod h1:vA6ryDfsN7py/3JApEst6nLTJboq66XsNcJGNmC88NQ= -github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -422,7 +320,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -433,16 +330,13 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= -github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo= -github.com/tsenart/vegeta/v12 v12.12.0/go.mod h1:gpdfR++WHV9/RZh4oux0f6lNPhsOH8pCjIGUlcPQe1M= -github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -451,11 +345,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= @@ -470,12 +359,11 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -486,7 +374,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -507,45 +394,14 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -566,8 +422,12 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -591,7 +451,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -600,31 +459,31 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -672,6 +531,9 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -705,7 +567,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -737,10 +598,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240823204242-4ba0660f739c/go.mod h1:gQizMG9jZ0L2ADJaM+JdZV4yTCON/CQpnHRPoM+54w4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -800,7 +659,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -810,23 +668,16 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= -k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= -k8s.io/code-generator v0.30.3/go.mod h1:PFgBiv+miFV7TZYp+RXgROkhA+sWYZ+mtpbMLofMke8= -k8s.io/gengo v0.0.0-20240404160639-a0386bf69313/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 h1:1Wof1cGQgA5pqgo8MxKPtf+qN6Sh/0JzznmeGPm1HnE= k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8/go.mod h1:Os6V6dZwLNii3vxFpxcNaTmH8LJJBkOTg1N0tOA0fvA= k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI= k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/caching v0.0.0-20240716132144-989f54c83776/go.mod h1:Uj74eO9rLiK1eb8wmDBED1hJBZQ7MJ9cvq/d8Ktsm3c= -knative.dev/hack v0.0.0-20240814130635-06f7aff93954/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= knative.dev/networking v0.0.0-20240815142417-37fdbdd0854b h1:ws/Jeho6on84+5tfNKLAKriVVGIwivHbgPEtZjBfcs0= knative.dev/networking v0.0.0-20240815142417-37fdbdd0854b/go.mod h1:2eMQVGLBZ5Kj1C4kKPuPhO7BsUeF6fkmhZFDQPIP+88= knative.dev/pkg v0.0.0-20240815051656-89743d9bbf7c h1:2crXVk4FG0dSG6WHaIT+WKbUzn7qG2wn0AfYmvA22zs= @@ -836,7 +687,6 @@ knative.dev/serving v0.42.2/go.mod h1:3cgU8/864RcqA0ZPrc3jFcmS3uJL/mOlUZiYsXonwa rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/gateway-api v0.8.0/go.mod h1:okOnjPNBFbIS/Rw9kAhuIUaIkLhTKEu+ARIuXk2dgaM= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/test/crds/gatewayapi_httproute.yaml b/test/crds/gatewayapi_httproute.yaml new file mode 100644 index 00000000000..bbecbc442fc --- /dev/null +++ b/test/crds/gatewayapi_httproute.yaml @@ -0,0 +1,5535 @@ +# +# Gateway API v1.2.1 Standard channel install +# + +# +# https://github.com/kubernetes-sigs/gateway-api/blob/v1.2.1/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +# +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.1 + gateway.networking.k8s.io/channel: standard + creationTimestamp: null + name: httproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: HTTPRoute + listKind: HTTPRouteList + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''')) : true))' + - message: sectionName must be unique when parentRefs includes 2 or + more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''')) : true))' + - message: sectionName must be unique when parentRefs includes 2 or + more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + required: + - backendRef + type: object + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null \ No newline at end of file diff --git a/test/crds/serving.kserve.io_inferenceservices.yaml b/test/crds/serving.kserve.io_inferenceservices.yaml index 732fc5bd602..03eea84bb73 100644 --- a/test/crds/serving.kserve.io_inferenceservices.yaml +++ b/test/crds/serving.kserve.io_inferenceservices.yaml @@ -1001,6 +1001,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -1335,10 +1337,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -1698,6 +1702,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -1711,6 +1722,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -1959,6 +1971,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -1966,6 +1979,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -1977,6 +1991,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -1985,6 +2000,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -2002,6 +2018,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -2963,6 +2980,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -3263,10 +3282,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -3626,6 +3647,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -3639,6 +3667,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -3887,6 +3916,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -3894,6 +3924,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -3905,6 +3936,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -3913,6 +3945,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -3930,6 +3963,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -4487,6 +4521,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -5269,6 +5305,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6283,6 +6321,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -6990,6 +7030,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -7746,6 +7788,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -8045,13 +8089,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -8136,6 +8177,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -8277,10 +8320,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -8640,6 +8685,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -8653,6 +8705,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -8901,6 +8954,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -8908,6 +8962,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -8919,6 +8974,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -8927,6 +8983,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -8944,6 +9001,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -9922,6 +9980,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -10662,6 +10722,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -11363,6 +11425,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12038,6 +12102,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -12751,6 +12817,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -13445,6 +13513,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -14143,6 +14213,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -14828,6 +14900,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15520,6 +15594,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -15783,13 +15859,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -15874,6 +15947,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -16343,6 +16418,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -17030,6 +17107,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -17795,6 +17874,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -18070,10 +18151,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -18433,6 +18516,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -18446,6 +18536,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -18694,6 +18785,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -18701,6 +18793,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -18712,6 +18805,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -18720,6 +18814,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -18737,6 +18832,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -19699,6 +19795,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -20404,6 +20502,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -21117,6 +21217,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -21397,13 +21499,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -21479,6 +21578,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -21619,10 +21720,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -21982,6 +22085,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -21995,6 +22105,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -22243,6 +22354,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -22250,6 +22362,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -22261,6 +22374,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -22269,6 +22383,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -22286,6 +22401,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -22796,6 +22912,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -23950,6 +24068,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -24706,6 +24826,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -25005,13 +25127,10 @@ spec: properties: name: type: string - source: - properties: - resourceClaimName: - type: string - resourceClaimTemplateName: - type: string - type: object + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string required: - name type: object @@ -25096,6 +25215,8 @@ spec: type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string sysctls: items: properties: @@ -25237,10 +25358,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -25600,6 +25723,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -25613,6 +25743,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -25861,6 +25992,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -25868,6 +26000,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -25879,6 +26012,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -25887,6 +26021,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -25904,6 +26039,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -26384,10 +26520,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -26636,6 +26774,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -26787,6 +26926,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -26794,6 +26934,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -26806,6 +26947,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -26814,6 +26956,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -26832,6 +26975,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -27987,6 +28131,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -28321,10 +28467,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -28684,6 +28832,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -28697,6 +28852,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -28945,6 +29101,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -28952,6 +29109,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -28963,6 +29121,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -28971,6 +29130,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -28988,6 +29148,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string @@ -29949,6 +30110,8 @@ spec: properties: name: type: string + request: + type: string required: - name type: object @@ -30249,10 +30412,12 @@ spec: diskURI: type: string fsType: + default: ext4 type: string kind: type: string readOnly: + default: false type: boolean required: - diskName @@ -30612,6 +30777,13 @@ spec: required: - path type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object iscsi: properties: chapAuthDiscovery: @@ -30625,6 +30797,7 @@ spec: iqn: type: string iscsiInterface: + default: default type: string lun: format: int32 @@ -30873,6 +31046,7 @@ spec: image: type: string keyring: + default: /etc/ceph/keyring type: string monitors: items: @@ -30880,6 +31054,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd type: string readOnly: type: boolean @@ -30891,6 +31066,7 @@ spec: type: object x-kubernetes-map-type: atomic user: + default: admin type: string required: - image @@ -30899,6 +31075,7 @@ spec: scaleIO: properties: fsType: + default: xfs type: string gateway: type: string @@ -30916,6 +31093,7 @@ spec: sslEnabled: type: boolean storageMode: + default: ThinProvisioned type: string storagePool: type: string diff --git a/test/e2e/batcher/test_batcher.py b/test/e2e/batcher/test_batcher.py index a076e1e0658..5c3a4084593 100644 --- a/test/e2e/batcher/test_batcher.py +++ b/test/e2e/batcher/test_batcher.py @@ -50,7 +50,7 @@ async def test_batcher(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/batcher/test_batcher_custom_port.py b/test/e2e/batcher/test_batcher_custom_port.py index 270b6de7913..0b7b1f90553 100644 --- a/test/e2e/batcher/test_batcher_custom_port.py +++ b/test/e2e/batcher/test_batcher_custom_port.py @@ -54,7 +54,7 @@ async def test_batcher_custom_port(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/batcher/test_raw_batcher.py b/test/e2e/batcher/test_raw_batcher.py index aeda31a7536..05b946d07e2 100644 --- a/test/e2e/batcher/test_raw_batcher.py +++ b/test/e2e/batcher/test_raw_batcher.py @@ -11,6 +11,7 @@ # limitations under the License. import os +import uuid from kubernetes import client from kserve import KServeClient @@ -31,8 +32,9 @@ @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_batcher_raw(rest_v1_client): - service_name = "isvc-raw-sklearn-batcher" +async def test_batcher_raw(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "isvc-raw-sklearn-batcher-" + suffix annotations = dict() annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" @@ -54,7 +56,7 @@ async def test_batcher_raw(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -83,7 +85,11 @@ async def test_batcher_raw(rest_v1_client): print(pod) raise e results = await predict_isvc( - rest_v1_client, service_name, "./data/iris_batch_input.json", is_batch=True + rest_v1_client, + service_name, + "./data/iris_batch_input.json", + is_batch=True, + network_layer=network_layer, ) assert all(x == results[0] for x in results) kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) diff --git a/test/e2e/common/utils.py b/test/e2e/common/utils.py index 2f9a8324b9c..72eaca81df9 100644 --- a/test/e2e/common/utils.py +++ b/test/e2e/common/utils.py @@ -39,8 +39,7 @@ STORAGE_URI_ENV = "STORAGE_URI" -def grpc_client(host): - cluster_ip = get_cluster_ip() +def grpc_client(host, cluster_ip): if ":" not in cluster_ip: cluster_ip = cluster_ip + ":80" logger.info("Cluster IP: %s", cluster_ip) @@ -62,6 +61,7 @@ async def predict_isvc( version=constants.KSERVE_V1BETA1_VERSION, model_name=None, is_batch=False, + network_layer: str = "istio", ) -> Union[InferResponse, Dict, List[Union[Dict, InferResponse]]]: kfs_client = KServeClient( config_file=os.environ.get("KUBECONFIG", "~/.kube/config") @@ -71,7 +71,7 @@ async def predict_isvc( namespace=KSERVE_TEST_NAMESPACE, version=version, ) - scheme, cluster_ip, host, path = get_isvc_endpoint(isvc) + scheme, cluster_ip, host, path = get_isvc_endpoint(isvc, network_layer) if model_name is None: model_name = service_name base_url = f"{scheme}://{cluster_ip}{path}" @@ -158,6 +158,7 @@ async def predict_ig( ig_name, input_path, version=constants.KSERVE_V1ALPHA1_VERSION, + network_layer: str = "istio", ) -> Union[InferResponse, Dict]: kserve_client = KServeClient( config_file=os.environ.get("KUBECONFIG", "~/.kube/config") @@ -167,22 +168,23 @@ async def predict_ig( namespace=KSERVE_TEST_NAMESPACE, version=version, ) - scheme, cluster_ip, host, _ = get_isvc_endpoint(ig) + scheme, cluster_ip, host, _ = get_isvc_endpoint(ig, network_layer) url = f"{scheme}://{cluster_ip}" return await predict(client, url, host, input_path, is_graph=True) -async def explain(service_name, input_path): - res = await explain_response(service_name, input_path) - return res["data"]["precision"] - - -async def explain_art(client, service_name, input_path): - res = await explain_response(client, service_name, input_path) +async def explain_art( + client, service_name, input_path, network_layer: str = "istio" +) -> Dict: + res = await explain_response( + client, service_name, input_path, network_layer=network_layer + ) return res["explanations"]["adversarial_prediction"] -async def explain_response(client, service_name, input_path) -> Dict: +async def explain_response( + client, service_name, input_path, network_layer: str +) -> Dict: kfs_client = KServeClient( config_file=os.environ.get("KUBECONFIG", "~/.kube/config") ) @@ -191,7 +193,7 @@ async def explain_response(client, service_name, input_path) -> Dict: namespace=KSERVE_TEST_NAMESPACE, version=constants.KSERVE_V1BETA1_VERSION, ) - scheme, cluster_ip, host, path = get_isvc_endpoint(isvc) + scheme, cluster_ip, host, path = get_isvc_endpoint(isvc, network_layer) url = f"{scheme}://{cluster_ip}{path}" headers = {"Host": host} with open(input_path) as json_file: @@ -227,11 +229,24 @@ async def explain_response(client, service_name, input_path) -> Dict: return response -def get_cluster_ip(name="istio-ingressgateway", namespace="istio-system"): +def get_cluster_ip(namespace="istio-system", labels: dict = None): cluster_ip = os.environ.get("KSERVE_INGRESS_HOST_PORT") if cluster_ip is None: api_instance = k8s_client.CoreV1Api(k8s_client.ApiClient()) - service = api_instance.read_namespaced_service(name, namespace) + if labels is None: + labels = { + "app": "istio-ingressgateway", + "istio": "ingressgateway", + } + label_selector = ",".join([f"{key}={value}" for key, value in labels.items()]) + services = api_instance.list_namespaced_service( + namespace, label_selector=label_selector + ) + if services.items: + service = services.items[0] + else: + raise RuntimeError(f"No service found with labels: {labels}") + if service.status.load_balancer.ingress is None: cluster_ip = service.spec.cluster_ip else: @@ -248,6 +263,7 @@ async def predict_grpc( parameters=None, version=constants.KSERVE_V1BETA1_VERSION, model_name=None, + network_layer: str = "istio", ) -> InferResponse: kfs_client = KServeClient( config_file=os.environ.get("KUBECONFIG", "~/.kube/config") @@ -257,11 +273,11 @@ async def predict_grpc( namespace=KSERVE_TEST_NAMESPACE, version=version, ) - _, _, host, _ = get_isvc_endpoint(isvc) + _, cluster_ip, host, _ = get_isvc_endpoint(isvc, network_layer) if model_name is None: model_name = service_name - client = grpc_client(host) + client = grpc_client(host, cluster_ip) response = await client.infer( InferRequest.from_grpc( @@ -292,14 +308,26 @@ async def predict_modelmesh( return response -def get_isvc_endpoint(isvc): +def get_isvc_endpoint(isvc, network_layer: str = "istio"): scheme = urlparse(isvc["status"]["url"]).scheme host = urlparse(isvc["status"]["url"]).netloc path = urlparse(isvc["status"]["url"]).path if os.environ.get("CI_USE_ISVC_HOST") == "1": cluster_ip = host - else: + elif network_layer == "istio" or network_layer == "istio-ingress": cluster_ip = get_cluster_ip() + elif network_layer == "envoy-gatewayapi": + cluster_ip = get_cluster_ip( + namespace="envoy-gateway-system", + labels={"serving.kserve.io/gateway": "kserve-ingress-gateway"}, + ) + elif network_layer == "istio-gatewayapi": + cluster_ip = get_cluster_ip( + namespace="kserve", + labels={"serving.kserve.io/gateway": "kserve-ingress-gateway"}, + ) + else: + raise ValueError(f"Unknown network layer {network_layer}") return scheme, cluster_ip, host, path @@ -308,6 +336,24 @@ def generate( input_json, version=constants.KSERVE_V1BETA1_VERSION, chat_completions=True, +): + url_suffix = "v1/chat/completions" if chat_completions else "v1/completions" + return _openai_request(service_name, input_json, version, url_suffix) + + +def embed( + service_name, + input_json, + version=constants.KSERVE_V1BETA1_VERSION, +): + return _openai_request(service_name, input_json, version, "v1/embeddings") + + +def _openai_request( + service_name, + input_json, + version=constants.KSERVE_V1BETA1_VERSION, + url_suffix="", ): with open(input_json) as json_file: data = json.load(json_file) @@ -323,10 +369,7 @@ def generate( scheme, cluster_ip, host, path = get_isvc_endpoint(isvc) headers = {"Host": host, "Content-Type": "application/json"} - if chat_completions: - url = f"{scheme}://{cluster_ip}{path}/openai/v1/chat/completions" - else: - url = f"{scheme}://{cluster_ip}{path}/openai/v1/completions" + url = f"{scheme}://{cluster_ip}{path}/openai/{url_suffix}" logger.info("Sending Header = %s", headers) logger.info("Sending url = %s", url) logger.info("Sending request data: %s", data) @@ -344,7 +387,11 @@ def generate( def is_model_ready( - rest_client, service_name, model_name, version=constants.KSERVE_V1BETA1_VERSION + rest_client, + service_name, + model_name, + version=constants.KSERVE_V1BETA1_VERSION, + network_layer: str = "istio", ): kfs_client = KServeClient( config_file=os.environ.get("KUBECONFIG", "~/.kube/config") @@ -354,7 +401,7 @@ def is_model_ready( namespace=KSERVE_TEST_NAMESPACE, version=version, ) - scheme, cluster_ip, host, path = get_isvc_endpoint(isvc) + scheme, cluster_ip, host, path = get_isvc_endpoint(isvc, network_layer) if model_name is None: model_name = service_name base_url = f"{scheme}://{cluster_ip}{path}" diff --git a/test/e2e/conftest.py b/test/e2e/conftest.py index 4ab42d06cb4..2ede547ed21 100644 --- a/test/e2e/conftest.py +++ b/test/e2e/conftest.py @@ -60,3 +60,17 @@ async def rest_v2_client(): ) yield v2_client await v2_client.close() + + +def pytest_addoption(parser): + parser.addoption( + "--network-layer", + default="istio", + type=str, + help="Network layer to used for testing. Default is istio. Allowed values are istio-ingress, envoy-gatewayapi, istio-gatewayapi", + ) + + +@pytest.fixture(scope="session") +def network_layer(request): + return request.config.getoption("--network-layer") diff --git a/test/e2e/custom/test_custom_model_grpc.py b/test/e2e/custom/test_custom_model_grpc.py index 6df68644b26..8dbd8a0e236 100644 --- a/test/e2e/custom/test_custom_model_grpc.py +++ b/test/e2e/custom/test_custom_model_grpc.py @@ -14,6 +14,7 @@ import base64 import json import os +import uuid import numpy as np import pytest @@ -65,7 +66,7 @@ async def test_custom_model_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -146,7 +147,7 @@ async def test_predictor_grpc_with_transformer_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -229,7 +230,7 @@ async def test_predictor_grpc_with_transformer_http(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -323,7 +324,7 @@ async def test_predictor_rest_with_transformer_rest(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -371,3 +372,92 @@ async def test_predictor_rest_with_transformer_rest(rest_v2_client): points = ["%.3f" % point for point in list(res.outputs[0].data)] assert points == ["14.976", "14.037", "13.966", "12.252", "12.086"] kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) + + +@pytest.mark.raw +@pytest.mark.asyncio(scope="session") +async def test_predictor_grpc_with_transformer_grpc_raw(network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "model-grpc-trans-grpc-raw-" + suffix + model_name = "custom-model" + + predictor = V1beta1PredictorSpec( + containers=[ + V1Container( + name="kserve-container", + image="kserve/custom-model-grpc:" + os.environ.get("GITHUB_SHA"), + resources=V1ResourceRequirements( + requests={"cpu": "50m", "memory": "128Mi"}, + limits={"cpu": "100m", "memory": "1Gi"}, + ), + ports=[ + V1ContainerPort( + container_port=8081, name="h2c-port", protocol="TCP" + ) + ], + args=["--model_name", model_name], + ) + ] + ) + + transformer = V1beta1TransformerSpec( + containers=[ + V1Container( + name="kserve-container", + image="kserve/custom-image-transformer-grpc:" + + os.environ.get("GITHUB_SHA"), + resources=V1ResourceRequirements( + requests={"cpu": "50m", "memory": "128Mi"}, + limits={"cpu": "100m", "memory": "1Gi"}, + ), + ports=[ + V1ContainerPort( + container_port=8081, name="grpc-port", protocol="TCP" + ) + ], + args=["--model_name", model_name, "--predictor_protocol", "grpc-v2"], + ) + ] + ) + + isvc = V1beta1InferenceService( + api_version=constants.KSERVE_V1BETA1, + kind=constants.KSERVE_KIND_INFERENCESERVICE, + metadata=client.V1ObjectMeta( + name=service_name, + namespace=KSERVE_TEST_NAMESPACE, + annotations={"serving.kserve.io/deploymentMode": "RawDeployment"}, + ), + spec=V1beta1InferenceServiceSpec(predictor=predictor, transformer=transformer), + ) + + kserve_client = KServeClient( + config_file=os.environ.get("KUBECONFIG", "~/.kube/config") + ) + kserve_client.create(isvc) + kserve_client.wait_isvc_ready(service_name, namespace=KSERVE_TEST_NAMESPACE) + + json_file = open("./data/custom_model_input.json") + data = json.load(json_file) + payload = [ + { + "name": "input-0", + "shape": [], + "datatype": "BYTES", + "contents": { + "bytes_contents": [ + base64.b64decode(data["instances"][0]["image"]["b64"]) + ] + }, + } + ] + response = await predict_grpc( + service_name=service_name, + payload=payload, + model_name=model_name, + network_layer=network_layer, + ) + fields = response.outputs[0].data + points = ["%.3f" % (point) for point in list(fields)] + assert points == ["14.976", "14.037", "13.966", "12.252", "12.086"] + kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) diff --git a/test/e2e/custom/test_ray.py b/test/e2e/custom/test_ray.py index a5426f5a885..4dd3ed4e298 100644 --- a/test/e2e/custom/test_ray.py +++ b/test/e2e/custom/test_ray.py @@ -52,7 +52,7 @@ async def test_custom_model_http_ray(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/data/text_embedding_input_openai_base64.json b/test/e2e/data/text_embedding_input_openai_base64.json new file mode 100644 index 00000000000..e0febd4120e --- /dev/null +++ b/test/e2e/data/text_embedding_input_openai_base64.json @@ -0,0 +1,5 @@ +{ + "input": ["This is an example sentence."], + "model": "hf-text-embedding-openai", + "encoding_format": "base64" +} diff --git a/test/e2e/data/text_embedding_input_openai_float.json b/test/e2e/data/text_embedding_input_openai_float.json new file mode 100644 index 00000000000..4eb7fb177bb --- /dev/null +++ b/test/e2e/data/text_embedding_input_openai_float.json @@ -0,0 +1,5 @@ +{ + "input": "This is an example sentence.", + "model": "hf-text-embedding-openai", + "encoding_format": "float" +} diff --git a/test/e2e/explainer/test_art_explainer.py b/test/e2e/explainer/test_art_explainer.py index 0d5a1147426..62fae056221 100644 --- a/test/e2e/explainer/test_art_explainer.py +++ b/test/e2e/explainer/test_art_explainer.py @@ -14,8 +14,11 @@ import logging import os +import uuid from kubernetes import client +from kubernetes.client import V1ResourceRequirements +import pytest from kserve import KServeClient from kserve import constants @@ -25,8 +28,6 @@ from kserve import V1beta1SKLearnSpec from kserve import V1beta1ARTExplainerSpec from kserve import V1beta1InferenceService -from kubernetes.client import V1ResourceRequirements -import pytest from ..common.utils import predict_isvc from ..common.utils import explain_art @@ -44,7 +45,7 @@ async def test_tabular_explainer(rest_v1_client): service_name = "art-explainer" isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -106,3 +107,82 @@ async def test_tabular_explainer(rest_v1_client): ) assert adv_prediction != 3 kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) + + +@pytest.mark.raw +@pytest.mark.asyncio(scope="session") +async def test_raw_tabular_explainer(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "art-explainer-raw-" + suffix + isvc = V1beta1InferenceService( + api_version=constants.KSERVE_V1BETA1, + kind=constants.KSERVE_KIND_INFERENCESERVICE, + metadata=client.V1ObjectMeta( + name=service_name, + namespace=KSERVE_TEST_NAMESPACE, + annotations={"serving.kserve.io/deploymentMode": "RawDeployment"}, + ), + spec=V1beta1InferenceServiceSpec( + predictor=V1beta1PredictorSpec( + sklearn=V1beta1SKLearnSpec( + storage_uri="gs://kfserving-examples/models/sklearn/mnist/art", + resources=V1ResourceRequirements( + requests={"cpu": "10m", "memory": "128Mi"}, + limits={"cpu": "100m", "memory": "256Mi"}, + ), + ) + ), + explainer=V1beta1ExplainerSpec( + min_replicas=1, + art=V1beta1ARTExplainerSpec( + type="SquareAttack", + name="explainer", + resources=V1ResourceRequirements( + requests={"cpu": "10m", "memory": "256Mi"}, + limits={"cpu": "100m", "memory": "512Mi"}, + ), + config={"nb_classes": "10"}, + ), + ), + ), + ) + + kserve_client.create(isvc) + try: + kserve_client.wait_isvc_ready( + service_name, namespace=KSERVE_TEST_NAMESPACE, timeout_seconds=720 + ) + except RuntimeError as e: + logging.info( + kserve_client.api_instance.get_namespaced_custom_object( + "serving.knative.dev", + "v1", + KSERVE_TEST_NAMESPACE, + "services", + service_name + "-predictor", + ) + ) + pods = kserve_client.core_api.list_namespaced_pod( + KSERVE_TEST_NAMESPACE, + label_selector="serving.kserve.io/inferenceservice={}".format(service_name), + ) + for pod in pods.items: + logging.info(pod) + raise e + + res = await predict_isvc( + rest_v1_client, + service_name, + "./data/mnist_input_bw_flat.json", + network_layer=network_layer, + ) + assert res["predictions"] == [3] + + adv_prediction = await explain_art( + rest_v1_client, + service_name, + "./data/mnist_input_bw.json", + network_layer=network_layer, + ) + assert adv_prediction != 3 + kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) diff --git a/test/e2e/graph/test_inference_graph.py b/test/e2e/graph/test_inference_graph.py index 5a39a075517..68e5c723888 100644 --- a/test/e2e/graph/test_inference_graph.py +++ b/test/e2e/graph/test_inference_graph.py @@ -64,7 +64,7 @@ async def test_inference_graph(rest_v1_client): ) sklearn_isvc_1 = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=sklearn_name_1, namespace=KSERVE_TEST_NAMESPACE ), @@ -72,7 +72,7 @@ async def test_inference_graph(rest_v1_client): ) sklearn_isvc_2 = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=sklearn_name_2, namespace=KSERVE_TEST_NAMESPACE ), @@ -91,7 +91,7 @@ async def test_inference_graph(rest_v1_client): ) xgb_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta(name=xgb_name, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=xgb_predictor), ) @@ -187,7 +187,7 @@ def construct_isvc_to_submit(service_name, image, model_name): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -924,11 +924,12 @@ async def test_ig_scenario10(rest_v1_client): @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_inference_graph_raw_mode(rest_v1_client): +async def test_inference_graph_raw_mode(rest_v1_client, network_layer): logger.info("Starting test test_inference_graph_raw_mode") - sklearn_name = "isvc-sklearn-graph-raw" - xgb_name = "isvc-xgboost-graph-raw" - graph_name = "model-chainer-raw" + suffix = str(uuid.uuid4())[1:6] + sklearn_name = "isvc-sklearn-graph-raw-" + suffix + xgb_name = "isvc-xgboost-graph-raw-" + suffix + graph_name = "model-chainer-raw-" + suffix annotations = dict() annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" @@ -945,7 +946,7 @@ async def test_inference_graph_raw_mode(rest_v1_client): ) sklearn_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=sklearn_name, namespace=KSERVE_TEST_NAMESPACE, @@ -966,7 +967,7 @@ async def test_inference_graph_raw_mode(rest_v1_client): ) xgb_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=xgb_name, namespace=KSERVE_TEST_NAMESPACE, @@ -1068,6 +1069,7 @@ async def test_inference_graph_raw_mode(rest_v1_client): # rest_v1_client, # graph_name, # os.path.join(IG_TEST_RESOURCES_BASE_LOCATION, "iris_input.json"), + # network_layer=network_layer, # ) # assert res["predictions"] == [1, 1] @@ -1078,11 +1080,12 @@ async def test_inference_graph_raw_mode(rest_v1_client): @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_inference_graph_raw_mode_with_hpa(rest_v1_client): +async def test_inference_graph_raw_mode_with_hpa(rest_v1_client, network_layer): logger.info("Starting test test_inference_graph_raw_mode_with_hpa") - sklearn_name = "isvc-sklearn-graph-raw-hpa" - xgb_name = "isvc-xgboost-graph-raw-hpa" - graph_name = "model-chainer-raw-hpa" + suffix = str(uuid.uuid4())[1:6] + sklearn_name = "isvc-sklearn-graph-raw-hpa-" + suffix + xgb_name = "isvc-xgboost-graph-raw-hpa-" + suffix + graph_name = "model-chainer-raw-hpa-" + suffix annotations = dict() annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" @@ -1103,7 +1106,7 @@ async def test_inference_graph_raw_mode_with_hpa(rest_v1_client): ) sklearn_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=sklearn_name, namespace=KSERVE_TEST_NAMESPACE, @@ -1124,7 +1127,7 @@ async def test_inference_graph_raw_mode_with_hpa(rest_v1_client): ) xgb_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=xgb_name, namespace=KSERVE_TEST_NAMESPACE, @@ -1231,6 +1234,7 @@ async def test_inference_graph_raw_mode_with_hpa(rest_v1_client): # rest_v1_client, # graph_name, # os.path.join(IG_TEST_RESOURCES_BASE_LOCATION, "iris_input.json"), + # network_layer=network_layer, # ) # assert res["predictions"] == [1, 1] diff --git a/test/e2e/helm/test_kserve_sklearn.py b/test/e2e/helm/test_kserve_sklearn.py index 22acd46725f..da12395a32d 100644 --- a/test/e2e/helm/test_kserve_sklearn.py +++ b/test/e2e/helm/test_kserve_sklearn.py @@ -61,7 +61,7 @@ async def test_sklearn_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/helm/test_model_mesh_sklearn.py b/test/e2e/helm/test_model_mesh_sklearn.py index a4ab83b0348..a45682cc3e3 100644 --- a/test/e2e/helm/test_model_mesh_sklearn.py +++ b/test/e2e/helm/test_model_mesh_sklearn.py @@ -58,7 +58,7 @@ async def test_sklearn_modelmesh(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta(name=service_name, annotations=annotations), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) diff --git a/test/e2e/logger/test_logger.py b/test/e2e/logger/test_logger.py index 75bf2f316b6..aa9016dbe25 100644 --- a/test/e2e/logger/test_logger.py +++ b/test/e2e/logger/test_logger.py @@ -52,7 +52,7 @@ async def test_kserve_logger(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta(name=msg_dumper, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) @@ -78,7 +78,7 @@ async def test_kserve_logger(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/logger/test_raw_logger.py b/test/e2e/logger/test_raw_logger.py index e8c8fa06fc0..e347aec5e46 100644 --- a/test/e2e/logger/test_raw_logger.py +++ b/test/e2e/logger/test_raw_logger.py @@ -13,6 +13,7 @@ import asyncio import os +import uuid from kubernetes import client from kserve import ( @@ -37,11 +38,12 @@ @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_kserve_logger(rest_v1_client): - msg_dumper = "message-dumper-raw" +async def test_kserve_logger(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + msg_dumper = "message-dumper-raw-" + suffix before(msg_dumper) - service_name = "isvc-logger-raw" + service_name = "isvc-logger-raw-" + suffix predictor = V1beta1PredictorSpec( min_replicas=1, logger=V1beta1LoggerSpec( @@ -61,11 +63,11 @@ async def test_kserve_logger(rest_v1_client): ), ), ) - base_test(msg_dumper, service_name, predictor, rest_v1_client) + await base_test(msg_dumper, service_name, predictor, rest_v1_client, network_layer) @pytest.mark.rawcipn -async def test_kserve_logger_cipn(rest_v1_client): +async def test_kserve_logger_cipn(rest_v1_client, network_layer): msg_dumper = "message-dumper-raw-cipn" before(msg_dumper) @@ -89,7 +91,7 @@ async def test_kserve_logger_cipn(rest_v1_client): ), ), ) - await base_test(msg_dumper, service_name, predictor, rest_v1_client) + await base_test(msg_dumper, service_name, predictor, rest_v1_client, network_layer) def before(msg_dumper): @@ -109,7 +111,7 @@ def before(msg_dumper): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=msg_dumper, namespace=KSERVE_TEST_NAMESPACE, annotations=annotations ), @@ -120,10 +122,10 @@ def before(msg_dumper): kserve_client.wait_isvc_ready(msg_dumper, namespace=KSERVE_TEST_NAMESPACE) -async def base_test(msg_dumper, service_name, predictor, rest_v1_client): +async def base_test(msg_dumper, service_name, predictor, rest_v1_client, network_layer): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, annotations=annotations ), @@ -141,7 +143,12 @@ async def base_test(msg_dumper, service_name, predictor, rest_v1_client): for pod in pods.items: print(pod) - res = await predict_isvc(rest_v1_client, service_name, "./data/iris_input.json") + res = await predict_isvc( + rest_v1_client, + service_name, + "./data/iris_input.json", + network_layer=network_layer, + ) assert res["predictions"] == [1, 1] pods = kserve_client.core_api.list_namespaced_pod( KSERVE_TEST_NAMESPACE, diff --git a/test/e2e/modelcache/__init__.py b/test/e2e/modelcache/__init__.py new file mode 100644 index 00000000000..0cdb835ca3f --- /dev/null +++ b/test/e2e/modelcache/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2024 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/e2e/modelcache/test_localmodelcache.py b/test/e2e/modelcache/test_localmodelcache.py new file mode 100644 index 00000000000..8291aa3c14f --- /dev/null +++ b/test/e2e/modelcache/test_localmodelcache.py @@ -0,0 +1,188 @@ +# Copyright 2024 The KServe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +import os + +import pytest +from kubernetes import client +from kubernetes.client import ( + V1ResourceRequirements, + V1PersistentVolumeSpec, + V1LocalVolumeSource, + V1VolumeNodeAffinity, + V1PersistentVolumeClaimSpec, +) +from kubernetes.client.exceptions import ApiException + +from kserve import constants +from kserve.api.kserve_client import KServeClient +from kserve.models.v1alpha1_local_model_node_group import V1alpha1LocalModelNodeGroup +from kserve.models.v1alpha1_local_model_node_group_spec import ( + V1alpha1LocalModelNodeGroupSpec, +) +from kserve.models.v1alpha1_local_model_cache import V1alpha1LocalModelCache +from kserve.models.v1alpha1_local_model_cache_spec import V1alpha1LocalModelCacheSpec +from kserve.models.v1beta1_inference_service import V1beta1InferenceService +from kserve.models.v1beta1_inference_service_spec import V1beta1InferenceServiceSpec +from kserve.models.v1beta1_predictor_spec import V1beta1PredictorSpec +from kserve.models.v1beta1_model_spec import V1beta1ModelSpec +from kserve.models.v1beta1_model_format import V1beta1ModelFormat +from ..common.utils import KSERVE_TEST_NAMESPACE, generate + + +@pytest.mark.modelcache +@pytest.mark.asyncio(scope="session") +async def test_vllm_modelcache(): + service_name = "opt-125m-chat-modelcache-worker1" + storage_uri = "hf://facebook/opt-125m" + nodes = ["minikube-m02", "minikube-m03"] + + pv_spec = V1PersistentVolumeSpec( + access_modes=["ReadWriteOnce"], + storage_class_name="standard", + capacity={"storage": "1Gi"}, + local=V1LocalVolumeSource(path="/models"), + persistent_volume_reclaim_policy="Delete", + node_affinity=V1VolumeNodeAffinity( + required=client.V1NodeSelector( + node_selector_terms=[ + client.V1NodeSelectorTerm( + match_expressions=[ + client.V1NodeSelectorRequirement( + key="kubernetes.io/hostname", + operator="In", + values=nodes, + ) + ] + ) + ] + ) + ), + ) + pvc_spec = V1PersistentVolumeClaimSpec( + access_modes=["ReadWriteOnce"], + resources=V1ResourceRequirements(requests={"storage": "1Gi"}), + storage_class_name="standard", + ) + + node_group = V1alpha1LocalModelNodeGroup( + api_version=constants.KSERVE_V1ALPHA1, + kind=constants.KSERVE_KIND_LOCALMODELNODEGROUP, + metadata=client.V1ObjectMeta( + name="opt-125m-nodegroup", + ), + spec=V1alpha1LocalModelNodeGroupSpec( + storage_limit="1Gi", + persistent_volume_spec=pv_spec, + persistent_volume_claim_spec=pvc_spec, + ), + ) + + model_cache = V1alpha1LocalModelCache( + api_version=constants.KSERVE_V1ALPHA1, + kind=constants.KSERVE_KIND_LOCALMODELCACHE, + metadata=client.V1ObjectMeta( + name="opt-125m", + ), + spec=V1alpha1LocalModelCacheSpec( + model_size="251Mi", + node_groups=[node_group.metadata.name], + source_model_uri=storage_uri, + ), + ) + + predictor = V1beta1PredictorSpec( + min_replicas=1, + model=V1beta1ModelSpec( + model_format=V1beta1ModelFormat( + name="huggingface", + ), + args=[ + "--model_name", + "hf-opt-125m-chat", + "--tokenizer_revision", + "27dcfa74d334bc871f3234de431e71c6eeba5dd6", + "--max_model_len", + "512", + ], + resources=V1ResourceRequirements( + requests={"cpu": "2", "memory": "6Gi"}, + limits={"cpu": "2", "memory": "6Gi"}, + ), + storage_uri=storage_uri, + ), + node_selector={"kubernetes.io/hostname": nodes[0]}, + ) + + isvc = V1beta1InferenceService( + api_version=constants.KSERVE_V1BETA1, + kind=constants.KSERVE_KIND_INFERENCESERVICE, + metadata=client.V1ObjectMeta( + name=service_name, namespace=KSERVE_TEST_NAMESPACE + ), + spec=V1beta1InferenceServiceSpec(predictor=predictor), + ) + + kserve_client = KServeClient( + config_file=os.environ.get("KUBECONFIG", "~/.kube/config") + ) + kserve_client.create_local_model_node_group(node_group) + kserve_client.create_local_model_cache(model_cache) + kserve_client.wait_local_model_cache_ready(model_cache.metadata.name, nodes=nodes) + kserve_client.create(isvc) + kserve_client.wait_isvc_ready(service_name, namespace=KSERVE_TEST_NAMESPACE) + k8s_client = kserve_client.api_instance + + # Test the model is cached on the correct nodes + worker_node_1_cache = k8s_client.get_cluster_custom_object( + constants.KSERVE_GROUP, + constants.KSERVE_V1ALPHA1_VERSION, + constants.KSERVE_PLURAL_LOCALMODELNODE, + "minikube-m02", + ) + worker_node_2_cache = k8s_client.get_cluster_custom_object( + constants.KSERVE_GROUP, + constants.KSERVE_V1ALPHA1_VERSION, + constants.KSERVE_PLURAL_LOCALMODELNODE, + "minikube-m03", + ) + assert ( + worker_node_1_cache["status"]["modelStatus"][model_cache.metadata.name] + == "ModelDownloaded" + ) + assert ( + worker_node_2_cache["status"]["modelStatus"][model_cache.metadata.name] + == "ModelDownloaded" + ) + + # Test the model is not cached on the controller node + with pytest.raises(ApiException): + k8s_client.get_cluster_custom_object( + constants.KSERVE_GROUP, + constants.KSERVE_V1ALPHA1_VERSION, + constants.KSERVE_PLURAL_LOCALMODELNODE, + "minikube", + ) + + res = generate(service_name, "./data/opt_125m_input_generate.json") + assert ( + res["choices"][0]["message"]["content"] + == "I'm not sure if this is a good idea, but I'm not sure if I should be" + ) + kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) + # Wait for the isvc to be deleted to avoid modelcache still in use error when deleting the model cache + await asyncio.sleep(30) + kserve_client.delete_local_model_cache(model_cache.metadata.name) + kserve_client.delete_local_model_node_group(node_group.metadata.name) diff --git a/test/e2e/predictor/test_autoscaling.py b/test/e2e/predictor/test_autoscaling.py index 42ed5f8e2f6..44c2bf8564a 100644 --- a/test/e2e/predictor/test_autoscaling.py +++ b/test/e2e/predictor/test_autoscaling.py @@ -13,6 +13,7 @@ # limitations under the License. import os +import uuid import pytest from kubernetes import client @@ -53,7 +54,7 @@ async def test_sklearn_kserve_concurrency(rest_v1_client): ) isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -98,7 +99,7 @@ async def test_sklearn_kserve_rps(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -146,7 +147,7 @@ async def test_sklearn_kserve_cpu(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, annotations=annotations ), @@ -174,8 +175,9 @@ async def test_sklearn_kserve_cpu(rest_v1_client): @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_sklearn_scale_raw(rest_v1_client): - service_name = "isvc-sklearn-scale-raw" +async def test_sklearn_scale_raw(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "isvc-sklearn-scale-raw-" + suffix predictor = V1beta1PredictorSpec( min_replicas=1, scale_metric="cpu", @@ -194,7 +196,7 @@ async def test_sklearn_scale_raw(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, annotations=annotations ), @@ -216,7 +218,9 @@ async def test_sklearn_scale_raw(rest_v1_client): ) assert hpa_resp["items"][0]["spec"]["targetCPUUtilizationPercentage"] == 50 - res = await predict_isvc(rest_v1_client, service_name, INPUT) + res = await predict_isvc( + rest_v1_client, service_name, INPUT, network_layer=network_layer + ) assert res["predictions"] == [1, 1] kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) @@ -224,7 +228,8 @@ async def test_sklearn_scale_raw(rest_v1_client): @pytest.mark.raw @pytest.mark.asyncio(scope="session") async def test_sklearn_rolling_update(): - service_name = "isvc-sklearn-rolling-update" + suffix = str(uuid.uuid4())[1:6] + service_name = "isvc-sklearn-rolling-update-" + suffix min_replicas = 4 predictor = V1beta1PredictorSpec( min_replicas=min_replicas, @@ -244,7 +249,7 @@ async def test_sklearn_rolling_update(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -260,7 +265,7 @@ async def test_sklearn_rolling_update(): updated_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, diff --git a/test/e2e/predictor/test_canary.py b/test/e2e/predictor/test_canary.py index 90db1d891f3..249c2b97cf2 100644 --- a/test/e2e/predictor/test_canary.py +++ b/test/e2e/predictor/test_canary.py @@ -50,7 +50,7 @@ def test_canary_rollout(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -75,7 +75,7 @@ def test_canary_rollout(): ) isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -116,7 +116,7 @@ def test_canary_rollout_runtime(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -144,7 +144,7 @@ def test_canary_rollout_runtime(): ) isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_grpc.py b/test/e2e/predictor/test_grpc.py index c0a075954d9..95b321f2452 100644 --- a/test/e2e/predictor/test_grpc.py +++ b/test/e2e/predictor/test_grpc.py @@ -58,7 +58,7 @@ async def test_custom_model_grpc(): logger_isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta(name=msg_dumper, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=logger_predictor), ) @@ -92,7 +92,7 @@ async def test_custom_model_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_huggingface.py b/test/e2e/predictor/test_huggingface.py index 545efbd7af9..f569813638e 100644 --- a/test/e2e/predictor/test_huggingface.py +++ b/test/e2e/predictor/test_huggingface.py @@ -11,13 +11,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import base64 import os import ast import pytest from kubernetes import client from kubernetes.client import V1ResourceRequirements +import numpy as np from kserve import ( V1beta1PredictorSpec, @@ -28,7 +29,7 @@ KServeClient, ) from kserve.constants import constants -from ..common.utils import KSERVE_TEST_NAMESPACE, generate, predict_isvc +from ..common.utils import KSERVE_TEST_NAMESPACE, generate, embed, predict_isvc from .test_output import ( huggingface_text_embedding_expected_output, huggingface_sequence_classification_with_probabilities_expected_output, @@ -65,7 +66,7 @@ def test_huggingface_openai_chat_completions(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -118,7 +119,7 @@ async def test_huggingface_v2_sequence_classification(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -166,7 +167,7 @@ async def test_huggingface_v1_fill_mask(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -219,7 +220,7 @@ async def test_huggingface_v2_token_classification(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -268,7 +269,7 @@ def test_huggingface_openai_text_2_text(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -324,7 +325,7 @@ async def test_huggingface_v2_text_embedding(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -345,6 +346,71 @@ async def test_huggingface_v2_text_embedding(rest_v2_client): kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) +@pytest.mark.llm +@pytest.mark.asyncio(scope="session") +async def test_huggingface_openai_text_embedding(): + service_name = "hf-text-embedding-openai" + predictor = V1beta1PredictorSpec( + min_replicas=1, + model=V1beta1ModelSpec( + model_format=V1beta1ModelFormat( + name="huggingface", + ), + args=[ + "--model_id", + "sentence-transformers/all-MiniLM-L6-v2", + "--model_revision", + "8b3219a92973c328a8e22fadcfa821b5dc75636a", + "--tokenizer_revision", + "8b3219a92973c328a8e22fadcfa821b5dc75636a", + "--task", + "text_embedding", + "--backend", + "huggingface", + ], + resources=V1ResourceRequirements( + requests={"cpu": "1", "memory": "2Gi"}, + limits={"cpu": "1", "memory": "4Gi"}, + ), + ), + ) + + isvc = V1beta1InferenceService( + api_version=constants.KSERVE_V1BETA1, + kind=constants.KSERVE_KIND_INFERENCESERVICE, + metadata=client.V1ObjectMeta( + name=service_name, namespace=KSERVE_TEST_NAMESPACE + ), + spec=V1beta1InferenceServiceSpec(predictor=predictor), + ) + + kserve_client = KServeClient( + config_file=os.environ.get("KUBECONFIG", "~/.kube/config") + ) + kserve_client.create(isvc) + kserve_client.wait_isvc_ready(service_name, namespace=KSERVE_TEST_NAMESPACE) + + # Validate float output + res = embed(service_name, "./data/text_embedding_input_openai_float.json") + assert len(res["data"]) == 1 + assert res["data"][0]["embedding"] == huggingface_text_embedding_expected_output + + # Validate base64 output. Decoded as the OpenAI library: + # https://github.com/openai/openai-python/blob/v1.59.7/src/openai/resources/embeddings.py#L118-L120 + res = embed(service_name, "./data/text_embedding_input_openai_base64.json") + embedding = np.frombuffer( + base64.b64decode(res["data"][0]["embedding"]), dtype="float32" + ).tolist() + assert len(res["data"]) == 1 + assert embedding == huggingface_text_embedding_expected_output + + # Validate Token count + assert res["usage"]["prompt_tokens"] == 8 + assert res["usage"]["total_tokens"] == 8 + + kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) + + @pytest.mark.llm @pytest.mark.asyncio(scope="session") async def test_huggingface_v2_sequence_classification_with_probabilities( @@ -379,7 +445,7 @@ async def test_huggingface_v2_sequence_classification_with_probabilities( isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_huggingface_vllm_openvino.py b/test/e2e/predictor/test_huggingface_vllm_openvino.py index c9bffe5399d..365376478c1 100644 --- a/test/e2e/predictor/test_huggingface_vllm_openvino.py +++ b/test/e2e/predictor/test_huggingface_vllm_openvino.py @@ -58,7 +58,7 @@ def test_huggingface_vllm_openvino_openai_chat_completions(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -108,7 +108,7 @@ def test_huggingface_vllm_openvino_openai_completions(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_lightgbm.py b/test/e2e/predictor/test_lightgbm.py index 32607b98465..cfa0171b824 100644 --- a/test/e2e/predictor/test_lightgbm.py +++ b/test/e2e/predictor/test_lightgbm.py @@ -52,7 +52,7 @@ async def test_lightgbm_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -91,7 +91,7 @@ async def test_lightgbm_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -146,7 +146,7 @@ async def test_lightgbm_v2_runtime_mlserver(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -199,7 +199,7 @@ async def test_lightgbm_v2_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -255,7 +255,7 @@ async def test_lightgbm_v2_grpc(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_mlflow.py b/test/e2e/predictor/test_mlflow.py index 05fe483ca7a..4b4c2c01769 100644 --- a/test/e2e/predictor/test_mlflow.py +++ b/test/e2e/predictor/test_mlflow.py @@ -59,7 +59,7 @@ async def test_mlflow_v2_runtime_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_multi_model_serving.py b/test/e2e/predictor/test_multi_model_serving.py index 58626375b54..516f0a2fc9d 100644 --- a/test/e2e/predictor/test_multi_model_serving.py +++ b/test/e2e/predictor/test_multi_model_serving.py @@ -66,7 +66,7 @@ async def test_mms_sklearn_kserve( isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -182,7 +182,7 @@ async def test_mms_xgboost_kserve( isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_paddle.py b/test/e2e/predictor/test_paddle.py index b4657407ff1..65c161f9488 100644 --- a/test/e2e/predictor/test_paddle.py +++ b/test/e2e/predictor/test_paddle.py @@ -51,7 +51,7 @@ async def test_paddle(rest_v1_client): service_name = "isvc-paddle" isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=V1ObjectMeta(name=service_name, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) @@ -99,7 +99,7 @@ async def test_paddle_runtime(rest_v1_client): service_name = "isvc-paddle-runtime" isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=V1ObjectMeta(name=service_name, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) @@ -148,7 +148,7 @@ async def test_paddle_v2_kserve(rest_v2_client): service_name = "isvc-paddle-v2-kserve" isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=V1ObjectMeta(name=service_name, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) @@ -205,7 +205,7 @@ async def test_paddle_v2_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=V1ObjectMeta(name=service_name, namespace=KSERVE_TEST_NAMESPACE), spec=V1beta1InferenceServiceSpec(predictor=predictor), ) diff --git a/test/e2e/predictor/test_pmml.py b/test/e2e/predictor/test_pmml.py index 07eed3051eb..f7c0922f1cb 100644 --- a/test/e2e/predictor/test_pmml.py +++ b/test/e2e/predictor/test_pmml.py @@ -49,7 +49,7 @@ async def test_pmml_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -98,7 +98,7 @@ async def test_pmml_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -144,7 +144,7 @@ async def test_pmml_v2_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -224,7 +224,7 @@ async def test_pmml_v2_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_raw_deployment.py b/test/e2e/predictor/test_raw_deployment.py index db9541c2ef8..572e7f88d4b 100644 --- a/test/e2e/predictor/test_raw_deployment.py +++ b/test/e2e/predictor/test_raw_deployment.py @@ -15,6 +15,7 @@ import base64 import json import os +import uuid from kubernetes import client from kubernetes.client import ( V1ResourceRequirements, @@ -41,8 +42,9 @@ @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_raw_deployment_kserve(rest_v1_client): - service_name = "raw-sklearn" +async def test_raw_deployment_kserve(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "raw-sklearn-" + suffix annotations = dict() annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" @@ -59,7 +61,7 @@ async def test_raw_deployment_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -73,15 +75,21 @@ async def test_raw_deployment_kserve(rest_v1_client): ) kserve_client.create(isvc) kserve_client.wait_isvc_ready(service_name, namespace=KSERVE_TEST_NAMESPACE) - res = await predict_isvc(rest_v1_client, service_name, "./data/iris_input.json") + res = await predict_isvc( + rest_v1_client, + service_name, + "./data/iris_input.json", + network_layer=network_layer, + ) assert res["predictions"] == [1, 1] kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) @pytest.mark.raw @pytest.mark.asyncio(scope="session") -async def test_raw_deployment_runtime_kserve(rest_v1_client): - service_name = "raw-sklearn-runtime" +async def test_raw_deployment_runtime_kserve(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "raw-sklearn-runtime-" + suffix annotations = dict() annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" @@ -101,7 +109,7 @@ async def test_raw_deployment_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -115,7 +123,12 @@ async def test_raw_deployment_runtime_kserve(rest_v1_client): ) kserve_client.create(isvc) kserve_client.wait_isvc_ready(service_name, namespace=KSERVE_TEST_NAMESPACE) - res = await predict_isvc(rest_v1_client, service_name, "./data/iris_input.json") + res = await predict_isvc( + rest_v1_client, + service_name, + "./data/iris_input.json", + network_layer=network_layer, + ) assert res["predictions"] == [1, 1] kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) @@ -126,8 +139,9 @@ async def test_raw_deployment_runtime_kserve(rest_v1_client): @pytest.mark.skip( "The custom-model-grpc image fails in OpenShift with a permission denied error" ) -async def test_isvc_with_multiple_container_port(): - service_name = "raw-multiport-custom-model" +async def test_isvc_with_multiple_container_port(network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "raw-multiport-custom-model-" + suffix model_name = "custom-model" predictor = V1beta1PredictorSpec( @@ -153,7 +167,7 @@ async def test_isvc_with_multiple_container_port(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -184,7 +198,10 @@ async def test_isvc_with_multiple_container_port(): ] expected_output = ["14.976", "14.037", "13.966", "12.252", "12.086"] grpc_response = await predict_grpc( - service_name=service_name, payload=payload, model_name=model_name + service_name=service_name, + payload=payload, + model_name=model_name, + network_layer=network_layer, ) fields = grpc_response.outputs[0].data grpc_output = ["%.3f" % value for value in fields] diff --git a/test/e2e/predictor/test_response_headers.py b/test/e2e/predictor/test_response_headers.py index 8a9c05dbac1..46e4cf7b815 100644 --- a/test/e2e/predictor/test_response_headers.py +++ b/test/e2e/predictor/test_response_headers.py @@ -62,7 +62,7 @@ def test_predictor_headers_v1(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -148,7 +148,7 @@ def test_predictor_headers_v2(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_sklearn.py b/test/e2e/predictor/test_sklearn.py index 0bd3eb77458..ef868dadc18 100644 --- a/test/e2e/predictor/test_sklearn.py +++ b/test/e2e/predictor/test_sklearn.py @@ -51,7 +51,7 @@ async def test_sklearn_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -93,7 +93,7 @@ async def test_sklearn_v2_mlserver(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -138,7 +138,7 @@ async def test_sklearn_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -185,7 +185,7 @@ async def test_sklearn_v2_runtime_mlserver(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -230,7 +230,7 @@ async def test_sklearn_v2(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -292,7 +292,7 @@ async def test_sklearn_v2_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -341,7 +341,7 @@ async def test_sklearn_v2_mixed(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -389,7 +389,7 @@ async def test_sklearn_v2_mixed_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_tensorflow.py b/test/e2e/predictor/test_tensorflow.py index 1985be35ba6..0135e9e241b 100644 --- a/test/e2e/predictor/test_tensorflow.py +++ b/test/e2e/predictor/test_tensorflow.py @@ -46,7 +46,7 @@ async def test_tensorflow_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -88,7 +88,7 @@ async def test_tensorflow_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_torchserve.py b/test/e2e/predictor/test_torchserve.py index 65fcc1deb6a..21d36da0b1a 100644 --- a/test/e2e/predictor/test_torchserve.py +++ b/test/e2e/predictor/test_torchserve.py @@ -52,7 +52,7 @@ async def test_torchserve_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -90,7 +90,7 @@ async def test_torchserve_v2_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -134,7 +134,7 @@ async def test_torchserve_grpc_v2(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -188,7 +188,7 @@ async def test_torchserve_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_triton.py b/test/e2e/predictor/test_triton.py index 5774216f9cd..fff24bb9f0f 100644 --- a/test/e2e/predictor/test_triton.py +++ b/test/e2e/predictor/test_triton.py @@ -48,7 +48,7 @@ async def test_triton(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -130,7 +130,7 @@ async def test_triton_runtime_with_transformer(rest_v1_client): ) isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/predictor/test_xgboost.py b/test/e2e/predictor/test_xgboost.py index ed059fc39c7..a231d2e897f 100644 --- a/test/e2e/predictor/test_xgboost.py +++ b/test/e2e/predictor/test_xgboost.py @@ -51,7 +51,7 @@ async def test_xgboost_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -96,7 +96,7 @@ async def test_xgboost_v2_mlserver(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -147,7 +147,7 @@ async def test_xgboost_single_model_file(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -191,7 +191,7 @@ async def test_xgboost_runtime_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -239,7 +239,7 @@ async def test_xgboost_v2_runtime_mlserver(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -284,7 +284,7 @@ async def test_xgboost_v2(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -333,7 +333,7 @@ async def test_xgboost_v2_grpc(): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/pytest.ini b/test/e2e/pytest.ini index 18c5d0120e7..3407bbfbc27 100644 --- a/test/e2e/pytest.ini +++ b/test/e2e/pytest.ini @@ -16,4 +16,5 @@ markers = predictor: predictor e2e tests including grpc path_based_routing: e2e tests for path based routing llm: e2e tests for huggingface runtime - vllm: e2e tests for huggingface runtime with vllm-openvino backend \ No newline at end of file + vllm: e2e tests for huggingface runtime with vllm-openvino backend + modelcache: e2e tests for model caching \ No newline at end of file diff --git a/test/e2e/qpext/test_qpext.py b/test/e2e/qpext/test_qpext.py index 6d4c39ff3a6..dfeb4a569ad 100644 --- a/test/e2e/qpext/test_qpext.py +++ b/test/e2e/qpext/test_qpext.py @@ -63,7 +63,7 @@ async def test_qpext_kserve(rest_v2_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, diff --git a/test/e2e/storagespec/test_s3_storagespec.py b/test/e2e/storagespec/test_s3_storagespec.py index 12e3229b5a3..9619dc59038 100644 --- a/test/e2e/storagespec/test_s3_storagespec.py +++ b/test/e2e/storagespec/test_s3_storagespec.py @@ -51,7 +51,7 @@ async def test_sklearn_s3_storagespec_kserve(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/e2e/transformer/test_collocation.py b/test/e2e/transformer/test_collocation.py index 83f11c8a9b2..68f9b798f0d 100644 --- a/test/e2e/transformer/test_collocation.py +++ b/test/e2e/transformer/test_collocation.py @@ -14,6 +14,7 @@ import os +import uuid from kubernetes import client from kserve import KServeClient @@ -90,7 +91,7 @@ async def test_transformer_collocation(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), @@ -134,8 +135,9 @@ async def test_transformer_collocation(rest_v1_client): @pytest.mark.skip( "The torchserve container fails in OpenShift with permission denied errors" ) -async def test_raw_transformer_collocation(rest_v1_client): - service_name = "raw-custom-model-collocation" +async def test_raw_transformer_collocation(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "raw-custom-model-collocation-" + suffix model_name = "mnist" predictor = V1beta1PredictorSpec( min_replicas=1, @@ -185,7 +187,7 @@ async def test_raw_transformer_collocation(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, @@ -217,10 +219,19 @@ async def test_raw_transformer_collocation(rest_v1_client): for pod in pods.items: print(pod) raise e - is_ready = await is_model_ready(rest_v1_client, service_name, model_name) is True + is_ready = ( + await is_model_ready( + rest_v1_client, service_name, model_name, network_layer=network_layer + ) + is True + ) assert is_ready is True res = await predict_isvc( - rest_v1_client, service_name, "./data/transformer.json", model_name=model_name + rest_v1_client, + service_name, + "./data/transformer.json", + model_name=model_name, + network_layer=network_layer, ) assert res["predictions"][0] == 2 kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) diff --git a/test/e2e/transformer/test_raw_transformer.py b/test/e2e/transformer/test_raw_transformer.py index 5ffd3f285e2..a3e345ac14b 100644 --- a/test/e2e/transformer/test_raw_transformer.py +++ b/test/e2e/transformer/test_raw_transformer.py @@ -12,7 +12,13 @@ # limitations under the License. import os +import uuid + from kubernetes import client +from kubernetes.client import V1ResourceRequirements +from kubernetes.client import V1Container +from kubernetes.client import V1EnvVar +import pytest from kserve import KServeClient from kserve import constants @@ -21,10 +27,7 @@ from kserve import V1beta1TorchServeSpec from kserve import V1beta1InferenceServiceSpec from kserve import V1beta1InferenceService -from kubernetes.client import V1ResourceRequirements -from kubernetes.client import V1Container -from kubernetes.client import V1EnvVar -import pytest + from ..common.utils import predict_isvc from ..common.utils import KSERVE_TEST_NAMESPACE @@ -34,8 +37,9 @@ @pytest.mark.skip( "The torchserve container fails in OpenShift with permission denied errors" ) -async def test_transformer(rest_v1_client): - service_name = "raw-transformer" +async def test_transformer(rest_v1_client, network_layer): + suffix = str(uuid.uuid4())[1:6] + service_name = "raw-transformer-" + suffix predictor = V1beta1PredictorSpec( min_replicas=1, pytorch=V1beta1TorchServeSpec( @@ -71,7 +75,7 @@ async def test_transformer(rest_v1_client): annotations["serving.kserve.io/deploymentMode"] = "RawDeployment" isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE, annotations=annotations ), @@ -97,7 +101,11 @@ async def test_transformer(rest_v1_client): raise e res = await predict_isvc( - rest_v1_client, service_name, "./data/transformer.json", model_name="mnist" + rest_v1_client, + service_name, + "./data/transformer.json", + model_name="mnist", + network_layer=network_layer, ) assert res["predictions"][0] == 2 kserve_client.delete(service_name, KSERVE_TEST_NAMESPACE) diff --git a/test/e2e/transformer/test_transformer.py b/test/e2e/transformer/test_transformer.py index 0de464188fc..19463bc37e4 100644 --- a/test/e2e/transformer/test_transformer.py +++ b/test/e2e/transformer/test_transformer.py @@ -67,7 +67,7 @@ async def test_transformer(rest_v1_client): isvc = V1beta1InferenceService( api_version=constants.KSERVE_V1BETA1, - kind=constants.KSERVE_KIND, + kind=constants.KSERVE_KIND_INFERENCESERVICE, metadata=client.V1ObjectMeta( name=service_name, namespace=KSERVE_TEST_NAMESPACE ), diff --git a/test/overlays/knative/knative-serving-istio.yaml b/test/overlays/knative/knative-serving-istio.yaml index 8dc6d08802d..952abaad4ac 100644 --- a/test/overlays/knative/knative-serving-istio.yaml +++ b/test/overlays/knative/knative-serving-istio.yaml @@ -9,7 +9,7 @@ metadata: name: knative-serving namespace: knative-serving spec: - version: "1.13.1" + version: "1.15.2" config: deployment: # Skip tag resolution for certain domains diff --git a/test/overlays/knative/knative-serving-kourier.yaml b/test/overlays/knative/knative-serving-kourier.yaml index 97268aba452..0208f8f6e74 100644 --- a/test/overlays/knative/knative-serving-kourier.yaml +++ b/test/overlays/knative/knative-serving-kourier.yaml @@ -9,7 +9,7 @@ metadata: name: knative-serving namespace: knative-serving spec: - version: "1.13.1" + version: "1.15.2" ingress: kourier: enabled: true diff --git a/test/scripts/gh-actions/build-images.sh b/test/scripts/gh-actions/build-images.sh index 19f8873734e..6b5212cfeec 100755 --- a/test/scripts/gh-actions/build-images.sh +++ b/test/scripts/gh-actions/build-images.sh @@ -25,6 +25,7 @@ set -o pipefail echo "Github SHA ${GITHUB_SHA}" CONTROLLER_IMG_TAG=${DOCKER_REPO}/${CONTROLLER_IMG}:${GITHUB_SHA} LOCALMODEL_CONTROLLER_IMG_TAG=${DOCKER_REPO}/${LOCALMODEL_CONTROLLER_IMG}:${GITHUB_SHA} +LOCALMODEL_AGENT_IMG_TAG=${DOCKER_REPO}/${LOCALMODEL_AGENT_IMG}:${GITHUB_SHA} STORAGE_INIT_IMG_TAG=${DOCKER_REPO}/${STORAGE_INIT_IMG}:${GITHUB_SHA} AGENT_IMG_TAG=${DOCKER_REPO}/${AGENT_IMG}:${GITHUB_SHA} ROUTER_IMG_TAG=${DOCKER_REPO}/${ROUTER_IMG}:${GITHUB_SHA} @@ -37,6 +38,10 @@ echo "Building localmodel controller image" docker buildx build -f localmodel.Dockerfile . -t "${LOCALMODEL_CONTROLLER_IMG_TAG}" \ -o type=docker,dest="${DOCKER_IMAGES_PATH}/${LOCALMODEL_CONTROLLER_IMG}-${GITHUB_SHA}",compression-level=0 +echo "Building localmodel agent image" +docker buildx build -f localmodel-agent.Dockerfile . -t "${LOCALMODEL_AGENT_IMG_TAG}" \ + -o type=docker,dest="${DOCKER_IMAGES_PATH}/${LOCALMODEL_AGENT_IMG}-${GITHUB_SHA}",compression-level=0 + echo "Building agent image" docker buildx build -f agent.Dockerfile . -t "${AGENT_IMG_TAG}" \ -o type=docker,dest="${DOCKER_IMAGES_PATH}/${AGENT_IMG}-${GITHUB_SHA}",compression-level=0 diff --git a/test/scripts/gh-actions/install-knative-operator.sh b/test/scripts/gh-actions/install-knative-operator.sh index e75052cb796..793610d6538 100755 --- a/test/scripts/gh-actions/install-knative-operator.sh +++ b/test/scripts/gh-actions/install-knative-operator.sh @@ -20,7 +20,7 @@ set -o errexit set -o nounset set -o pipefail -KNATIVE_OPERATOR_VERSION="v1.14.5" +KNATIVE_OPERATOR_VERSION="v1.16.0" echo "Installing Knative Operator ..." helm install knative-operator --namespace knative-operator --create-namespace --wait \ diff --git a/test/scripts/gh-actions/run-e2e-tests.sh b/test/scripts/gh-actions/run-e2e-tests.sh index e3d460fb9f0..88ab0ea2308 100755 --- a/test/scripts/gh-actions/run-e2e-tests.sh +++ b/test/scripts/gh-actions/run-e2e-tests.sh @@ -15,6 +15,7 @@ # limitations under the License. # The script is used to deploy knative and kserve, and run e2e tests. +# Usage: run-e2e-tests.sh $MARKER $PARALLELISM $NETWORK_LAYER set -o errexit set -o nounset @@ -27,8 +28,16 @@ else echo "No parallelism requested for pytest. Will use default value of 1" fi +MARKER="${1}" PARALLELISM="${2:-1}" +NETWORK_LAYER="${3:-'istio'}" + source python/kserve/.venv/bin/activate pushd test/e2e >/dev/null - pytest -m "$1" --ignore=qpext --log-cli-level=INFO -n $PARALLELISM --dist worksteal + if [[ $MARKER == "raw" && $NETWORK_LAYER == "istio-ingress" ]]; then + echo "Skipping explainer tests for raw deployment with ingress" + pytest -m "$MARKER" --ignore=qpext --log-cli-level=INFO -n $PARALLELISM --dist worksteal --network-layer $NETWORK_LAYER --ignore=explainer/ + else + pytest -m "$MARKER" --ignore=qpext --log-cli-level=INFO -n $PARALLELISM --dist worksteal --network-layer $NETWORK_LAYER + fi popd diff --git a/test/scripts/gh-actions/setup-deps.sh b/test/scripts/gh-actions/setup-deps.sh index b187897ff46..6f751027d69 100755 --- a/test/scripts/gh-actions/setup-deps.sh +++ b/test/scripts/gh-actions/setup-deps.sh @@ -16,51 +16,76 @@ # The script will install KServe dependencies in the GH Actions environment. # (Istio, Knative, cert-manager, kustomize, yq) +# Usage: setup-deps.sh $DEPLOYMENT_MODE $NETWORK_LAYER set -o errexit set -o nounset set -o pipefail -SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )"; +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd 2>/dev/null)" DEPLOYMENT_MODE="${1:-'serverless'}" +NETWORK_LAYER="${2:-'istio'}" -ISTIO_VERSION="1.20.4" -CERT_MANAGER_VERSION="v1.15.1" +ISTIO_VERSION="1.23.2" +CERT_MANAGER_VERSION="v1.16.1" YQ_VERSION="v4.28.1" +GATEWAY_API_VERSION="v1.2.1" +ENVOY_GATEWAY_VERSION="v1.2.2" echo "Installing yq ..." wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64 -O /usr/local/bin/yq && chmod +x /usr/local/bin/yq -echo "Installing Istio ..." -mkdir istio_tmp -pushd istio_tmp >/dev/null +if [[ $NETWORK_LAYER == "istio-gatewayapi" || $NETWORK_LAYER == "envoy-gatewayapi" ]]; then + echo "Installing Gateway CRDs ..." + kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/${GATEWAY_API_VERSION}/standard-install.yaml +fi + +if [[ $NETWORK_LAYER == "istio-ingress" || $NETWORK_LAYER == "istio-gatewayapi" || $NETWORK_LAYER == "istio" ]]; then + echo "Installing Istio ..." + mkdir istio_tmp + pushd istio_tmp >/dev/null curl -L https://istio.io/downloadIstio | ISTIO_VERSION=${ISTIO_VERSION} sh - cd istio-${ISTIO_VERSION} export PATH=$PWD/bin:$PATH - istioctl manifest generate --set meshConfig.accessLogFile=/dev/stdout > ${SCRIPT_DIR}/../../overlays/istio/generated-manifest.yaml -popd + istioctl manifest generate --set meshConfig.accessLogFile=/dev/stdout >${SCRIPT_DIR}/../../overlays/istio/generated-manifest.yaml + popd + kubectl create ns istio-system + for i in {1..3}; do kubectl apply -k test/overlays/istio && break || sleep 15; done -kubectl create ns istio-system -for i in 1 2 3 ; do kubectl apply -k test/overlays/istio && break || sleep 15; done + echo "Waiting for Istio to be ready ..." + kubectl wait --for=condition=Ready pods --all --timeout=240s -n istio-system +elif [[ $NETWORK_LAYER == "envoy-gatewayapi" ]]; then + echo "Installing Envoy Gateway ..." + helm install eg oci://docker.io/envoyproxy/gateway-helm --version ${ENVOY_GATEWAY_VERSION} -n envoy-gateway-system --create-namespace --wait + kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available -echo "Waiting for Istio to be ready ..." -kubectl wait --for=condition=Ready pods --all --timeout=240s -n istio-system + echo "Creating envoy GatewayClass ..." + cat <