From 3ee95070c3fb8c99378c27af0358986f5b75e872 Mon Sep 17 00:00:00 2001 From: cvicens Date: Mon, 26 May 2025 16:36:32 +0200 Subject: [PATCH 01/18] name in pvc --- gitops/model/templates/model-pvc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitops/model/templates/model-pvc.yaml b/gitops/model/templates/model-pvc.yaml index 2ca9f32..1499c68 100644 --- a/gitops/model/templates/model-pvc.yaml +++ b/gitops/model/templates/model-pvc.yaml @@ -2,10 +2,10 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: models-pvc + name: {{ .Values.model.name }}-pvc namespace: "{{ .Values.dataScienceProjectNamespace }}" labels: - app: models-pvc + app: {{ .Values.model.name }}-pvc annotations: argocd.argoproj.io/hook: PreSync argocd.argoproj.io/hook-delete-policy: HookFailed From 8bc86fe3449c2211a00908fb1d22eb8b24219750 Mon Sep 17 00:00:00 2001 From: cvicens Date: Mon, 26 May 2025 18:09:52 +0200 Subject: [PATCH 02/18] fixed name of pvc --- gitops/model/templates/setup-jobs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitops/model/templates/setup-jobs.yaml b/gitops/model/templates/setup-jobs.yaml index b176367..ff100f8 100644 --- a/gitops/model/templates/setup-jobs.yaml +++ b/gitops/model/templates/setup-jobs.yaml @@ -69,4 +69,4 @@ spec: volumes: - name: models-volume persistentVolumeClaim: - claimName: models-pvc + claimName: {{ .Values.model.name }}-pvc From 25d620bbe7da155eac9ed530755c6a816c9063c8 Mon Sep 17 00:00:00 2001 From: cvicens Date: Mon, 26 May 2025 20:11:46 +0200 Subject: [PATCH 03/18] not needed --- gitops/embeddings/Chart.yaml | 5 - gitops/embeddings/README.md | 190 ------------------ gitops/embeddings/run.sh | 23 --- .../embeddings/templates/model-instance.yaml | 92 --------- gitops/embeddings/templates/model-pvc.yaml | 17 -- .../templates/model-s3-connection.yaml | 22 -- gitops/embeddings/templates/namespace.yaml | 16 -- .../embeddings/templates/setup-jobs-rbac.yaml | 56 ------ gitops/embeddings/templates/setup-jobs.yaml | 85 -------- gitops/embeddings/values.yaml | 53 ----- 10 files changed, 559 deletions(-) delete mode 100644 gitops/embeddings/Chart.yaml delete mode 100644 gitops/embeddings/README.md delete mode 100755 gitops/embeddings/run.sh delete mode 100644 gitops/embeddings/templates/model-instance.yaml delete mode 100644 gitops/embeddings/templates/model-pvc.yaml delete mode 100644 gitops/embeddings/templates/model-s3-connection.yaml delete mode 100644 gitops/embeddings/templates/namespace.yaml delete mode 100644 gitops/embeddings/templates/setup-jobs-rbac.yaml delete mode 100644 gitops/embeddings/templates/setup-jobs.yaml delete mode 100644 gitops/embeddings/values.yaml diff --git a/gitops/embeddings/Chart.yaml b/gitops/embeddings/Chart.yaml deleted file mode 100644 index 481bc46..0000000 --- a/gitops/embeddings/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v2 -name: embeddings-server -description: A Helm chart to deploy embeddings models using RHOAI -version: 0.1.0 -appVersion: "1.0" diff --git a/gitops/embeddings/README.md b/gitops/embeddings/README.md deleted file mode 100644 index 30b74c0..0000000 --- a/gitops/embeddings/README.md +++ /dev/null @@ -1,190 +0,0 @@ -# Deploying Nomic AI - -## Deploy the Application object in charge of deploying the Model - -Adapt the following parameters to your environment: - -- model.connection.scheme: http(s) -- model.connection.awsAccessKeyId: user to access the S3 server -- model.connection.awsSecretAccessKey: user key -- model.connection.awsDefaultRegion: region, none in MinIO -- model.connection.awsS3Bucket: bucket name -- model.connection.awsS3Endpoint: host and port (minio.ic-shared-minio.svc:9000) - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: nomic-embeddings - namespace: openshift-gitops - annotations: - argocd.argoproj.io/compare-options: IgnoreExtraneous - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -spec: - project: default - destination: - server: 'https://kubernetes.default.svc' - namespace: embeddings # DATA_SCIENCE_PROJECT_NAMESPACE used later - source: - path: gitops/embeddings - repoURL: https://github.com/alpha-hack-program/model-serving-utils.git - targetRevision: main - helm: - parameters: - - name: createNamespace # This has to be false if deploying in the an existing namespace - value: 'true' - - name: model.connection.createSecret # This has to be false if the secret `embeddings` already exists - value: 'true' - - name: dataScienceProjectNamespace - value: "embeddings" # DATA_SCIENCE_PROJECT_NAMESPACE used later - - name: dataScienceProjectDisplayName - value: "embeddings" - - name: model.root - value: nomic-ai - - name: model.id - value: nomic-embed-text-v1 - - name: model.name - value: nomic-embed-text-v1 - - name: model.displayName - value: "Nomic Embed Text v1" - - name: model.runtime.displayName - value: "Nomic BERT" - - name: model.runtime.templateName - value: "nomic-bert-template" - # - name: model.accelerator.productName - # value: "NVIDIA-A10G" - # - name: model.accelerator.min - # value: '1' - # - name: model.accelerator.max - # value: '1' - syncPolicy: - automated: - # prune: true - selfHeal: true -``` -## Create a secret called hf-creds in the namespace ${DATA_SCIENCE_PROJECT_NAMESPACE} - -```sh -HF_USERNAME=xyz -HF_TOKEN=hf_********** -DATA_SCIENCE_PROJECT_NAMESPACE=embeddings - -oc create secret generic hf-creds \ - --from-literal=HF_USERNAME=${HF_USERNAME} \ - --from-literal=HF_TOKEN=${HF_TOKEN} \ - -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -``` - -## Test - -```sh -DATA_SCIENCE_PROJECT_NAMESPACE=embeddings -RUNTIME_MODEL_ID="nomic-embed-text-v1" -INFERENCE_URL=$(oc get inferenceservice/${RUNTIME_MODEL_ID} -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -o jsonpath='{.status.url}') -echo ${INFERENCE_URL} - -curl -s -X 'POST' \ - "${INFERENCE_URL}/v1/embeddings" \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "model": "'${RUNTIME_MODEL_ID}'", - "input": ["En un lugar de la Mancha..."] -}' -``` - -# Deploying Nomic AI with GPU - -## Deploy the Application object in charge of deploying the Model - -Adapt the following parameters to your environment: - -- model.connection.scheme: http(s) -- model.connection.awsAccessKeyId: user to access the S3 server -- model.connection.awsSecretAccessKey: user key -- model.connection.awsDefaultRegion: region, none in MinIO -- model.connection.awsS3Bucket: bucket name -- model.connection.awsS3Endpoint: host and port (minio.ic-shared-minio.svc:9000) - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: nomic-embeddings-gpu - namespace: openshift-gitops - annotations: - argocd.argoproj.io/compare-options: IgnoreExtraneous - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -spec: - project: default - destination: - server: 'https://kubernetes.default.svc' - namespace: embeddings # DATA_SCIENCE_PROJECT_NAMESPACE used later - source: - path: gitops/embeddings - repoURL: https://github.com/alpha-hack-program/model-serving-utils.git - targetRevision: main - helm: - parameters: - - name: createNamespace # This has to be false if deploying in the an existing namespace - value: 'false' - - name: model.connection.createSecret # This has to be false if the secret `embeddings` already exists - value: 'false' - - name: dataScienceProjectNamespace - value: "embeddings" # DATA_SCIENCE_PROJECT_NAMESPACE used later - - name: dataScienceProjectDisplayName - value: "embeddings" - - name: model.root - value: nomic-ai - - name: model.id - value: nomic-embed-text-v1 - - name: model.name - value: nomic-embed-text-v1-gpu - - name: model.displayName - value: "Nomic Embed Text v1 GPU" - - name: model.runtime.displayName - value: "Nomic BERT" - - name: model.runtime.templateName - value: "nomic-bert-template" - - name: model.accelerator.productName - value: "NVIDIA-A10G" - - name: model.accelerator.min - value: '1' - - name: model.accelerator.max - value: '1' - syncPolicy: - automated: - # prune: true - selfHeal: true -``` -## Create a secret called hf-creds in the namespace ${DATA_SCIENCE_PROJECT_NAMESPACE} - -```sh -HF_USERNAME=xyz -HF_TOKEN=hf_********** -DATA_SCIENCE_PROJECT_NAMESPACE=embeddings - -oc create secret generic hf-creds \ - --from-literal=HF_USERNAME=${HF_USERNAME} \ - --from-literal=HF_TOKEN=${HF_TOKEN} \ - -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -``` - -## Test - -```sh -DATA_SCIENCE_PROJECT_NAMESPACE=embeddings -RUNTIME_MODEL_ID="nomic-embed-text-v1-gpu" -INFERENCE_URL=$(oc get inferenceservice/${RUNTIME_MODEL_ID} -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -o jsonpath='{.status.url}') -echo ${INFERENCE_URL} - -time curl -s -X 'POST' \ - "${INFERENCE_URL}/v1/embeddings" \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "model": "'${RUNTIME_MODEL_ID}'", - "input": ["En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, salpicón las más noches, duelos y quebrantos los sábados, lantejas los viernes, algún palomino de añadidura los domingos, consumían las tres partes de su hacienda. El resto della concluían sayo de velarte, calzas de velludo para las fiestas, con sus pantuflos de lo mesmo, y los días de entresemana se honraba con su vellorí de lo más fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que así ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro hidalgo con los cincuenta años; era de complexión recia, seco de carnes, enjuto de rostro, gran madrugador y amigo de la caza. Quieren decir que tenía el sobrenombre de Quijada, o Quesada, que en esto hay alguna diferencia en los autores que deste caso escriben; aunque por conjeturas verosímiles se deja entender que se llamaba Quijana. Pero esto importa poco a nuestro cuento: basta que en la narración dél no se salga un punto de la verdad. Es, pues, de saber que este sobredicho hidalgo, los ratos que estaba ocioso, que eran los más del año, se daba a leer libros de caballerías, con tanta afición y gusto, que olvidó casi de todo punto el ejercicio de la caza, y aun la administración de su hacienda; y llegó a tanto su curiosidad y desatino en esto, que vendió muchas hanegas de tierra de sembradura para comprar libros de caballerías en que leer, y así, llevó a su casa todos cuantos pudo haber dellos; y de todos, ningunos le parecían tan bien como los que compuso el famoso Feliciano de Silva; porque la claridad de su prosa y aquellas entricadas razones suyas le parecían de perlas, y más cuando llegaba a leer aquellos requiebros y cartas de desafíos, donde en muchas partes hallaba escrito: «La razón de la sinrazón que a mi razón se hace, de tal manera mi razón enflaquece, que con razón me quejo de la vuestra fermosura». Y también cuando leía: «... los altos cielos que de vuestra divinidad divinamente con las estrellas os fortifican, y os hacen merecedora del merecimiento que merece la vuestra grandeza». Con estas razones perdía el pobre caballero el juicio, y desvelábase por entenderlas y desentrañarles el sentido, que no se lo sacara ni las entendiera el mesmo Aristóteles, si resucitara para sólo ello. No estaba muy bien con las heridas que don Belianís daba y recebía, porque se imaginaba que, por grandes maestros que le hubiesen curado, no dejaría de tener el rostro y todo el cuerpo lleno de cicatrices y señales. Pero, con todo, alababa en su autor aquel acabar su libro con la promesa de aquella inacabable aventura, y muchas veces le vino deseo de tomar la pluma y dalle fin al pie de la letra, como allí se promete; y sin duda alguna lo hiciera, y aun saliera con ello, si otros mayores y continuos pensamientos no se lo estorbaran. Tuvo muchas veces competencia con el cura de su lugar (que era hombre docto, graduado en Sigüenza), sobre cuál había sido mejor caballero: Palmerín de Ingalaterra, o Amadís de Gaula; mas maese Nicolás, barbero del mismo pueblo, decía que ninguno llegaba al Caballero del Febo, y que si alguno se le podía comparar, era don Galaor, hermano de Amadís de Gaula, porque tenía muy acomodada condición para todo; que no era caballero melindroso, ni tan llorón como su hermano, y que en lo de la valentía no le iba en zaga. En resolución, él se enfrascó tanto en su lectura, que se le pasaban las noches leyendo de claro en claro, y los días de turbio en turbio; y así, del poco dormir y del mucho leer se le secó el celebro de manera, que vino a perder el juicio. Llenósele la fantasía de todo aquello que leía en los libros, así de encantamentos como de pendencias, batallas, desafíos, heridas, requiebros, amores, tormentas y disparates imposibles; y asentósele de tal modo en la imaginación que era verdad toda aquella máquina de aquellas soñadas invenciones que leía, que para él no había otra historia más cierta en el mundo. Decía él que el Cid Ruy Díaz había sido muy buen caballero; pero que no tenía que ver con el Caballero de la Ardiente Espada, que de sólo un revés había partido por medio dos fieros y descomunales gigantes. Mejor estaba con Bernardo del Carpio, porque en Roncesvalles había muerto a Roldán el encantado, valiéndose de la industria de Hércules, cuando ahogó a Anteon, el hijo de la Tierra, entre los brazos. Decía mucho bien del gigante Morgante, porque, con ser de aquella generación gigantea, que todos son soberbios y descomedidos, él solo era afable y bien criado. Pero, sobre todos, estaba bien con Reinaldos de Montalbán, y más cuando le veía salir de su castillo y robar cuantos topaba, y cuando en allende robó aquel ídolo de Mahoma que era todo de oro, según dice su historia. Diera él, por dar una mano de coces al traidor de Galalón, al ama que tenía, y aun a su sobrina de añadidura. En efeto, rematado ya su juicio, vino a dar en el más extraño pensamiento que jamás dio loco en el mundo; y fue que le pareció convenible y necesario, así para el aumento de su honra como para el servicio de su república, hacerse caballero andante, y irse por todo el mundo con sus armas y caballo a buscar las aventuras y a ejercitarse en todo aquello que él había leído que los caballeros andantes se ejercitaban, deshaciendo todo género de agravio, y poniéndose en ocasiones y peligros donde, acabándolos, cobrase eterno nombre y fama. Imaginábase el pobre ya coronado por el valor de su brazo, por lo menos, del imperio de Trapisonda; y así, con estos tan agradables pensamientos, llevado del extraño gusto que en ellos sentía, se dio priesa a poner en efeto lo que deseaba. Y lo primero que hizo fue limpiar unas armas que habían sido de sus bisabuelos, que, tomadas de orín y llenas de moho, luengos siglos había que estaban puestas y olvidadas en un rincón. Limpiólas y aderezólas lo mejor que pudo, pero vio que tenían una gran falta, y era que no tenían celada de encaje, sino morrión simple; mas a esto suplió su industria, porque de cartones hizo un modo de media celada, que, encajada con el morrión, hacían una apariencia de celada entera. Es verdad que para probar si era fuerte y podía estar al riesgo de una cuchillada, sacó su espada y le dio dos golpes, y con el primero y en un punto deshizo lo que había hecho en una semana; y no dejó de parecerle mal la facilidad con que la había hecho pedazos, y, por asegurarse deste peligro, la tornó a hacer de nuevo, poniéndole unas barras de hierro por de dentro, de tal manera, que él quedó satisfecho de su fortaleza y, sin querer hacer nueva experiencia della, la diputó y tuvo por celada finísima de encaje. Fue luego a ver su rocín, y aunque tenía más cuartos que un real y más tachas que el caballo de Gonela, que tantum pellis et ossa fuit, le pareció que ni el Bucéfalo de Alejandro ni Babieca el del Cid con él se igualaban. Cuatro días se le pasaron en imaginar qué nombre le pondría; porque (según se decía él a sí mesmo) no era razón que caballo de caballero tan famoso, y tan bueno él por sí, estuviese sin nombre conocido; y ansí, procuraba acomodársele de manera que declarase quién había sido antes que fuese de caballero andante, y lo que era entonces; pues estaba muy puesto en razón que, mudando su señor estado, mudase él también el nombre, y le cobrase famoso y de estruendo, como convenía a la nueva orden y al nuevo ejercicio que ya profesaba; y así, después de muchos nombres que formó, borró y quitó, añadió, deshizo y tornó a hacer en su memoria e imaginación, al fin le vino a llamar Rocinante, nombre, a su parecer, alto, sonoro y significativo de lo que había sido cuando fue rocín, antes de lo que ahora era, que era antes y primero de todos los rocines del mundo. Puesto nombre, y tan a su gusto, a su caballo, quiso ponérsele a sí mismo, y en este pensamiento duró otros ocho días, y al cabo se vino a llamar don Quijote; de donde, como queda dicho, tomaron ocasión los autores desta tan verdadera historia que, sin duda, se debía de llamar Quijada, y no Quesada, como otros quisieron decir. Pero, acordándose que el valeroso Amadís no sólo se había contentado con llamarse Amadís a secas, sino que añadió el nombre de su reino y patria, por hacerla famosa, y se llamó Amadís de Gaula, así quiso, como buen caballero, añadir al suyo el nombre de la suya y llamarse don Quijote de la Mancha, con que, a su parecer, declaraba muy al vivo su linaje y patria, y la honraba con tomar el sobrenombre della. Limpias, pues, sus armas, hecho del morrión celada, puesto nombre a su rocín y confirmándose a sí mismo, se dio a entender que no le faltaba otra cosa sino buscar una dama de quien enamorarse: porque el caballero andante sin amores era árbol sin hojas y sin fruto y cuerpo sin alma. Decíase él: «Si yo, por malos de mis pecados, o por mi buena suerte, me encuentro por ahí con algún gigante, como de ordinario les acontece a los caballeros andantes, y le derribo de un encuentro, o le parto por mitad del cuerpo, o, finalmente, le venzo y le rindo, ¿no será bien tener a quien enviarle presentado, y que entre y se hinque de rodillas ante mi dulce señora, y diga con voz humilde y rendida: «Yo, señora, soy el gigante Caraculiambro, señor de la ínsula Malindrania, a quien venció en singular batalla el jamás como se debe alabado caballero don Quijote de la Mancha, el cual me mandó que me presentase ante vuestra merced, para que la vuestra grandeza disponga de mí a su talante»? ¡Oh, cómo se holgó nuestro buen caballero cuando hubo hecho este discurso, y más cuando halló a quien dar nombre de su dama! Y fue, a lo que se cree, que en un lugar cerca del suyo había una moza labradora de muy buen parecer, de quien él un tiempo anduvo enamorado, aunque, según se entiende, ella jamás lo supo, ni le dio cata dello. Llamábase Aldonza Lorenzo, y a ésta le pareció ser bien darle título de señora de sus pensamientos; y, buscándole nombre que no desdijese mucho del suyo, y que tirase y se encaminase al de princesa y gran señora, vino a llamarla Dulcinea del Toboso; porque era natural del Toboso; nombre, a su parecer, músico y peregrino y significativo, como todos los demás que a él y a sus cosas había puesto."] -}' -``` - diff --git a/gitops/embeddings/run.sh b/gitops/embeddings/run.sh deleted file mode 100755 index 1fce8a9..0000000 --- a/gitops/embeddings/run.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -ARGOCD_APP_NAME=vllm-mistral-7b - -# Load environment variables -DATA_SCIENCE_PROJECT_NAMESPACE="embeddings" - - # --set model.accelerator.productName="NVIDIA-A10G" \ - # --set model.accelerator.min=1 \ - # --set model.accelerator.max=1 \ - -helm template . --name-template ${ARGOCD_APP_NAME} \ - --set createNamespace="true" \ - --set createSecret="true" \ - --set dataScienceProjectNamespace=${DATA_SCIENCE_PROJECT_NAMESPACE} \ - --set dataScienceProjectDisplayName=${DATA_SCIENCE_PROJECT_NAMESPACE} \ - --set model.root=nomic-ai \ - --set model.id=nomic-embed-text \ - --set model.name=nomic-embed \ - --set model.displayName="Nomic AI Tesxt" \ - --set model.accelerator.productName="NVIDIA-A10G" \ - --set model.accelerator.min=1 \ - --set model.accelerator.max=1 \ - --include-crds \ No newline at end of file diff --git a/gitops/embeddings/templates/model-instance.yaml b/gitops/embeddings/templates/model-instance.yaml deleted file mode 100644 index 3712c94..0000000 --- a/gitops/embeddings/templates/model-instance.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -apiVersion: serving.kserve.io/v1beta1 -kind: InferenceService -metadata: - annotations: - argocd.argoproj.io/sync-wave: "2" - openshift.io/display-name: "{{ .Values.model.displayName }}" - security.opendatahub.io/enable-auth: '{{ .Values.model.enableAuth }}' - {{- if .Values.model.rawDeployment }} - serving.kserve.io/deploymentMode: RawDeployment - {{- else }} - serving.knative.openshift.io/enablePassthrough: 'true' - sidecar.istio.io/inject: 'true' - sidecar.istio.io/rewriteAppHTTPProbers: 'true' - {{- end }} - name: {{ .Values.model.name }} - namespace: {{ .Values.dataScienceProjectNamespace }} - labels: - opendatahub.io/dashboard: 'true' -spec: - predictor: - maxReplicas: {{ .Values.model.maxReplicas }} - minReplicas: 1 - model: - modelFormat: - name: {{ .Values.model.format }} - name: '' - resources: - limits: - # If model has accelerator and max is set, use min value - {{- if and .Values.model.accelerator .Values.model.accelerator.max }} - nvidia.com/gpu: '{{ .Values.model.accelerator.max }}' - {{- end }} - cpu: '{{ .Values.model.runtime.resources.limits.cpu }}' - memory: '{{ .Values.model.runtime.resources.limits.memory }}' - requests: - # If model has accelerator and min is set, use min value - {{- if and .Values.model.accelerator .Values.model.accelerator.min }} - nvidia.com/gpu: '{{ .Values.model.accelerator.min }}' - {{- end }} - cpu: '{{ .Values.model.runtime.resources.requests.cpu }}' - memory: '{{ .Values.model.runtime.resources.requests.memory }}' - runtime: {{ .Values.model.name }} - storage: - key: aws-connection-{{ .Values.model.connection.name }} - path: "{{ printf "%s/%s" .Values.model.root .Values.model.id }}" - {{- if .Values.model.accelerator }} - tolerations: - - effect: NoSchedule - key: nvidia.com/gpu - operator: Exists - nodeSelector: - nvidia.com/gpu.product: {{ .Values.model.accelerator.productName }} - {{- end }} ---- -apiVersion: serving.kserve.io/v1alpha1 -kind: ServingRuntime -metadata: - annotations: - argocd.argoproj.io/sync-wave: "2" - opendatahub.io/accelerator-name: migrated-gpu - opendatahub.io/apiProtocol: {{ .Values.model.apiProtocol }} - opendatahub.io/template-display-name: "{{ .Values.model.runtime.templateDisplayName }}" - opendatahub.io/template-name: "{{ .Values.model.runtime.templateName }}" - openshift.io/display-name: "{{ .Values.model.displayName }}" - name: {{ .Values.model.name }} - labels: - opendatahub.io/dashboard: 'true' -spec: - builtInAdapter: - modelLoadingTimeoutMillis: 90000 - annotations: - prometheus.io/path: /metrics - prometheus.io/port: '8080' - containers: - - args: - - '--model-path=/mnt/models' - - '--trust-remote-code=True' - {{- if .Values.model.accelerator }} - image: '{{ .Values.runtime.gpuImage }}' - {{- else }} - image: '{{ .Values.runtime.cpuImage }}' - {{- end }} - name: kserve-container - ports: - - containerPort: 8080 - name: http1 - protocol: TCP - multiModel: false - supportedModelFormats: - - autoSelect: true - name: {{ .Values.model.format }} diff --git a/gitops/embeddings/templates/model-pvc.yaml b/gitops/embeddings/templates/model-pvc.yaml deleted file mode 100644 index 27eb2d4..0000000 --- a/gitops/embeddings/templates/model-pvc.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ .Values.model.name }}-models-pvc - namespace: "{{ .Values.dataScienceProjectNamespace }}" - labels: - model: {{ .Values.model.name }} - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: HookFailed -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Gi \ No newline at end of file diff --git a/gitops/embeddings/templates/model-s3-connection.yaml b/gitops/embeddings/templates/model-s3-connection.yaml deleted file mode 100644 index bfe3bc9..0000000 --- a/gitops/embeddings/templates/model-s3-connection.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Create secret if instructed to do so -{{- if .Values.model.connection.createSecret }} -kind: Secret -apiVersion: v1 -metadata: - name: aws-connection-{{ .Values.model.connection.name }} - namespace: {{ .Values.dataScienceProjectNamespace }} - labels: - opendatahub.io/dashboard: 'true' - opendatahub.io/managed: 'true' - annotations: - opendatahub.io/connection-type: {{ .Values.model.connection.type }} - openshift.io/display-name: {{ .Values.model.connection.displayName }} -stringData: - AWS_ACCESS_KEY_ID: {{ .Values.model.connection.awsAccessKeyId }} - AWS_SECRET_ACCESS_KEY: {{ .Values.model.connection.awsSecretAccessKey }} - AWS_DEFAULT_REGION: {{ .Values.model.connection.awsDefaultRegion }} - AWS_S3_BUCKET: {{ .Values.model.connection.awsS3Bucket }} - AWS_S3_ENDPOINT: {{ printf "%s://%s" .Values.model.connection.scheme .Values.model.connection.awsS3Endpoint }} - -type: Opaque -{{- end }} \ No newline at end of file diff --git a/gitops/embeddings/templates/namespace.yaml b/gitops/embeddings/templates/namespace.yaml deleted file mode 100644 index 1b6ab82..0000000 --- a/gitops/embeddings/templates/namespace.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -{{- if .Values.createNamespace }} -apiVersion: v1 -kind: Namespace -metadata: - name: "{{ .Values.dataScienceProjectNamespace }}" - annotations: - argocd.argoproj.io/sync-wave: "-1" - openshift.io/description: "{{ .Values.dataScienceProjectDisplayName }}" - openshift.io/display-name: '{{ .Values.dataScienceProjectDisplayName }}' - labels: - argocd.argoproj.io/managed-by: {{ .Values.argocdNamespace }} #argocd instance ns - kubernetes.io/metadata.name: "{{ .Values.dataScienceProjectNamespace }}" - modelmesh-enabled: 'false' - opendatahub.io/dashboard: 'true' -{{- end }} \ No newline at end of file diff --git a/gitops/embeddings/templates/setup-jobs-rbac.yaml b/gitops/embeddings/templates/setup-jobs-rbac.yaml deleted file mode 100644 index a5c16ed..0000000 --- a/gitops/embeddings/templates/setup-jobs-rbac.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -# Cluster Role named embeddings-route-reader that can reader openshift routes -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation - name: {{ .Values.model.name }}-route-reader - namespace: {{ .Values.dataScienceProjectNamespace }} -rules: -- apiGroups: ["route.openshift.io"] - resources: ["routes"] - verbs: ["get", "list", "watch"] ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation - name: {{ .Values.model.name }}-setup-job - namespace: {{ .Values.dataScienceProjectNamespace }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation - name: {{ .Values.model.name }}-setup-job-edit - namespace: {{ .Values.dataScienceProjectNamespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edit -subjects: -- kind: ServiceAccount - name: {{ .Values.model.name }}-setup-job ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation - name: {{ .Values.model.name }}-route-reader-binding - namespace: {{ .Values.dataScienceProjectNamespace }} -subjects: -- kind: ServiceAccount - name: {{ .Values.model.name }}-setup-job - namespace: {{ .Values.dataScienceProjectNamespace }} -roleRef: - kind: Role - name: {{ .Values.model.name }}-route-reader - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/gitops/embeddings/templates/setup-jobs.yaml b/gitops/embeddings/templates/setup-jobs.yaml deleted file mode 100644 index 36b7726..0000000 --- a/gitops/embeddings/templates/setup-jobs.yaml +++ /dev/null @@ -1,85 +0,0 @@ ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: job-{{ .Values.model.name | lower }}-model-setup - namespace: "{{ .Values.dataScienceProjectNamespace }}" - annotations: - argocd.argoproj.io/hook: PreSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation -spec: - selector: {} - backoffLimit: 10 - template: - spec: - containers: - - args: - - -ec - - |- - echo -n 'Waiting for hf-creds secret' - while ! oc get secret hf-creds 2>/dev/null; do - echo -n . - sleep 5 - done; echo - - MODELS_MOUNT_PATH=/mnt/models - HF_USERNAME=$(oc get secret hf-creds -o jsonpath='{.data.HF_USERNAME}' | base64 -d) - HF_TOKEN=$(oc get secret hf-creds -o jsonpath='{.data.HF_TOKEN}' | base64 -d) - MODEL_ROOT="{{ .Values.model.root }}" - MODEL_ID="{{ .Values.model.id }}" - - # Check if MODELS_MOUNT_PATH exists and fail if it doesn't - if [ ! -d "${MODELS_MOUNT_PATH}" ]; then - echo "Directory '${MODELS_MOUNT_PATH}' does not exist. Exiting..." - exit 1 - fi - - - huggingface-cli download ${MODEL_ROOT}/${MODEL_ID} --token ${HF_TOKEN} \ - --cache-dir ${MODELS_MOUNT_PATH}/.cache \ - --local-dir ${MODELS_MOUNT_PATH}/${MODEL_ROOT}/${MODEL_ID} - - # Set up AWS CLI - AWS_CONFIG_FILE=/scratch/aws-config - AWS_S3_BUCKET={{ .Values.model.connection.awsS3Bucket }} - AWS_ACCESS_KEY_ID={{ .Values.model.connection.awsAccessKeyId }} - AWS_SECRET_ACCESS_KEY={{ .Values.model.connection.awsSecretAccessKey }} - AWS_DEFAULT_REGION={{ .Values.model.connection.awsDefaultRegion }} - AWS_S3_ENDPOINT={{ .Values.model.connection.awsS3Endpoint }} - AWS_S3_CUSTOM_DOMAIN=${AWS_S3_ENDPOINT} - AWS_S3_USE_PATH_STYLE=1 - - cat << EOF > ${AWS_CONFIG_FILE} - [default] - aws_access_key_id = ${AWS_ACCESS_KEY_ID} - aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY} - region = ${AWS_DEFAULT_REGION} - EOF - - # Check if the bucket exists and create it if it doesn't - echo ">>>>>> Checking if S3 bucket exists..." - if aws s3api head-bucket --bucket ${AWS_S3_BUCKET} --endpoint-url "{{ .Values.model.connection.scheme }}://${AWS_S3_ENDPOINT}" 2>&1 | grep -q "Not Found"; then - echo "Bucket ${AWS_S3_BUCKET} does not exist. Creating..." - aws s3api create-bucket --bucket ${AWS_S3_BUCKET} --endpoint-url "{{ .Values.model.connection.scheme }}://${AWS_S3_ENDPOINT}" - else - echo "Bucket ${AWS_S3_BUCKET} already exists. Continuing..." - fi - - # Upload the model to the bucket excluding safetensor files - echo ">>>>>> Uploading model to AWS_S3_BUCKET ${AWS_S3_BUCKET}" - aws s3 sync ${MODELS_MOUNT_PATH}/${MODEL_ROOT}/${MODEL_ID} s3://${AWS_S3_BUCKET}/${MODEL_ROOT}/${MODEL_ID}/ --exclude ".git/*" --exclude ".git" --endpoint-url "{{ .Values.model.connection.scheme }}://${AWS_S3_ENDPOINT}" - command: - - /bin/bash - image: {{ .Values.setup.image }} - imagePullPolicy: Always - name: create-ds-connections - volumeMounts: - - name: models-volume - mountPath: /mnt/models - restartPolicy: Never - serviceAccount: {{ .Values.model.name }}-setup-job - serviceAccountName: {{ .Values.model.name }}-setup-job - volumes: - - name: models-volume - persistentVolumeClaim: - claimName: {{ .Values.model.name }}-models-pvc diff --git a/gitops/embeddings/values.yaml b/gitops/embeddings/values.yaml deleted file mode 100644 index 665fe0b..0000000 --- a/gitops/embeddings/values.yaml +++ /dev/null @@ -1,53 +0,0 @@ -argocdNamespace: openshift-gitops - -dataScienceProjectDisplayName: embeddings -dataScienceProjectNamespace: embeddings - -createNamespace: true - -model: - root: nomic-ai - id: nomic-embed-text-v1 - name: nomic-embed-text-v1 - displayName: Nomic AI Embed Text v1 - maxReplicas: 1 - format: pytorch - apiProtocol: REST - enableAuth: false - rawDeployment: true - runtime: - templateName: nomic-serving-template - templateDisplayName: Nomic Serving Template - resources: - limits: - cpu: '2' - memory: 8Gi - requests: - cpu: '1' - memory: 4Gi - # accelerator: - # max: '1' - # min: '1' - # productName: NVIDIA-A10G - connection: - name: embeddings - createSecret: true - displayName: embeddings - type: s3 - scheme: http - awsAccessKeyId: minio - awsSecretAccessKey: minio123 - awsDefaultRegion: none - awsS3Bucket: models - awsS3Endpoint: minio.ic-shared-minio.svc:9000 - volumes: - shm: - sizeLimit: 2Gi - -runtime: - gpuImage: quay.io/rh-aiservices-bu/sbert-runtime:1.2.0 - cpuImage: quay.io/rh-aiservices-bu/sbert-runtime-cpu:1.2.0 - - -setup: - image: quay.io/atarazana/hf-cli:latest \ No newline at end of file From 7f8550eab9ee7a7f856f5420832c6e3d4daa8110 Mon Sep 17 00:00:00 2001 From: cvicens Date: Wed, 6 Aug 2025 18:17:04 +0200 Subject: [PATCH 04/18] reorg --- components/.containerignore | 13 ++ components/.gitignore | 20 ++ components/Containerfile | 19 ++ components/build-component.sh | 35 +++ components/push-component.sh | 25 ++ components/register_model/build.sh | 7 - .../register_model/compile-upsert-pipeline.sh | 47 ++-- .../register_model/model-registries.yaml | 197 ---------------- components/register_model/pipeline.py | 78 +++++++ components/register_model/push.sh | 6 - components/register_model/pyproject.toml | 2 +- .../register_model_component.py | 199 ---------------- .../register_model_component.yaml | 219 ------------------ components/register_model/requirements.txt | 2 +- components/register_model/run.sh | 6 - .../register_model.cpython-312.pyc | Bin 4837 -> 0 bytes .../component_metadata/register_model.yaml | 18 +- .../register_model/src/register_model.py | 185 +++++++++++---- .../src/runtime-requirements.txt | 2 +- components/register_model/src/test.py | 163 +++++++++++++ components/register_model/src/test.sh | 20 ++ components/register_model/src/utils.py | 125 ---------- components/register_model/uv.lock | 8 +- components/run-component.sh | 26 +++ components/shared/__init__.py | 0 components/shared/kubeflow.py | 163 +++++++++++++ components/shared/utils.py | 51 ++++ deploy-model.sh | 2 +- gitops/model/README.md | 2 +- 29 files changed, 807 insertions(+), 833 deletions(-) create mode 100644 components/.containerignore create mode 100644 components/.gitignore create mode 100644 components/Containerfile create mode 100755 components/build-component.sh create mode 100755 components/push-component.sh delete mode 100755 components/register_model/build.sh delete mode 100644 components/register_model/model-registries.yaml create mode 100644 components/register_model/pipeline.py delete mode 100755 components/register_model/push.sh delete mode 100644 components/register_model/register_model_component.py delete mode 100644 components/register_model/register_model_component.yaml delete mode 100755 components/register_model/run.sh delete mode 100644 components/register_model/src/__pycache__/register_model.cpython-312.pyc create mode 100644 components/register_model/src/test.py create mode 100755 components/register_model/src/test.sh delete mode 100644 components/register_model/src/utils.py create mode 100755 components/run-component.sh create mode 100644 components/shared/__init__.py create mode 100644 components/shared/kubeflow.py create mode 100644 components/shared/utils.py diff --git a/components/.containerignore b/components/.containerignore new file mode 100644 index 0000000..390f091 --- /dev/null +++ b/components/.containerignore @@ -0,0 +1,13 @@ +**/__pycache__ +**/.git +**/.DS_Store +**/*.old +**/*.log +**/*.pyc +**/*.bkp +**/.venv +**/.vscode +**/.pytest_cache +**/component_metadata +Dockerfile +Containerfile diff --git a/components/.gitignore b/components/.gitignore new file mode 100644 index 0000000..7b03564 --- /dev/null +++ b/components/.gitignore @@ -0,0 +1,20 @@ +!*.yaml +__pycache__/ +# Ignore all Python bytecode files +*.py[cod] +# Ignore all Python cache directories +*.pyc +# Ignore all Python egg files +*.egg +# Ignore all Python distribution files +*.whl +# Ignore all Python virtual environment directories +.venv/ +# Ignore all Jupyter Notebook checkpoints +.ipynb_checkpoints/ +# Ignore all log files +*.log +# Ignore all coverage reports +*.coverage +# Ignore all test output files +*.test \ No newline at end of file diff --git a/components/Containerfile b/components/Containerfile new file mode 100644 index 0000000..29d5740 --- /dev/null +++ b/components/Containerfile @@ -0,0 +1,19 @@ +# Generated by KFP. +# Updated manually to include shared directory + +ARG BASE_IMAGE + +FROM ${BASE_IMAGE} + +ARG COMPONENT_NAME + +WORKDIR /usr/local/src/kfp/components + +COPY ${COMPONENT_NAME}/src/runtime-requirements.txt runtime-requirements.txt + +RUN pip install --no-cache-dir -r runtime-requirements.txt +RUN pip install --no-cache-dir kfp==2.8.0 + +COPY ${COMPONENT_NAME}/src/ . +COPY shared ./shared + diff --git a/components/build-component.sh b/components/build-component.sh new file mode 100755 index 0000000..751c35f --- /dev/null +++ b/components/build-component.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Source the .env file +. .env + +# If there is not exactly one argument and is not in the COMPONENTS array, print usage and exit +if [ "$#" -ne 1 ] || ! [[ " ${COMPONENTS[@]} " =~ " ${1} " ]]; then + echo "Usage: $0 ${COMPONENTS[@]}" + exit 1 +fi + +# Set the COMPONENT_NAME variable to the first argument +COMPONENT_NAME=$1 + +# Source the component-specific environment variables if the file exists +[ -f ${COMPONENT_NAME}/.env ] && . ${COMPONENT_NAME}/.env + +# Print info +echo "COMPONENT_NAME: ${COMPONENT_NAME}" +echo "BASE_IMAGE: ${BASE_IMAGE}" +echo "REGISTRY: ${REGISTRY}" +echo "TAG: ${TAG}" +export COMPONENT_NAME +export BASE_IMAGE +export REGISTRY +export TAG + +# Build the component using the kfp CLI +export PYTHONPATH=${PYTHONPATH}:$(pwd)/${COMPONENT_NAME}/src:$(pwd)/shared +kfp component build ${COMPONENT_NAME}/src/ --component-filepattern ${COMPONENT_NAME}.py --no-push-image --no-build-image + +# Build the image using the BASE_IMAGE build arg +podman build -t ${COMPONENT_NAME}:${TAG} -f ./Containerfile . \ + --build-arg BASE_IMAGE=${BASE_IMAGE} \ + --build-arg COMPONENT_NAME=${COMPONENT_NAME} diff --git a/components/push-component.sh b/components/push-component.sh new file mode 100755 index 0000000..11ea82b --- /dev/null +++ b/components/push-component.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Source the .env file +. .env + +# If there is not exactly one argument and is not in the COMPONENTS array, print usage and exit +if [ "$#" -ne 1 ] || ! [[ " ${COMPONENTS[@]} " =~ " ${1} " ]]; then + echo "Usage: $0 ${COMPONENTS[@]}" + exit 1 +fi + +# Set the COMPONENT_NAME variable to the first argument +COMPONENT_NAME=$1 + +# Source the component-specific environment variables if the file exists +[ -f ${COMPONENT_NAME}/.env ] && . ${COMPONENT_NAME}/.env + +# Print info +echo "COMPONENT_NAME: ${COMPONENT_NAME}" +echo "BASE_IMAGE: ${BASE_IMAGE}" +echo "REGISTRY: ${REGISTRY}" +echo "TAG: ${TAG}" + +podman tag localhost/${COMPONENT_NAME}:${TAG} ${REGISTRY}/${COMPONENT_NAME}:${TAG} +podman push ${REGISTRY}/${COMPONENT_NAME}:${TAG} diff --git a/components/register_model/build.sh b/components/register_model/build.sh deleted file mode 100755 index 696eb9d..0000000 --- a/components/register_model/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -. .env - -kfp component build src/ --component-filepattern ${COMPONENT_NAME}.py --no-push-image --overwrite-dockerfile --no-build-image - -podman build -t ${COMPONENT_NAME}:latest -f src/Dockerfile src/ diff --git a/components/register_model/compile-upsert-pipeline.sh b/components/register_model/compile-upsert-pipeline.sh index 3eb6c88..7013a1e 100755 --- a/components/register_model/compile-upsert-pipeline.sh +++ b/components/register_model/compile-upsert-pipeline.sh @@ -1,22 +1,29 @@ #!/bin/bash -. .env +# Load base environment +. $(dirname "$(pwd)")/.env -# Check if parameter compile_only is set to true -if [ "$1" == "compile_only" ]; then - echo "Compile only mode." +# Source the component-specific environment variables if the file exists +[ -f ./.env ] && . ./.env - python register_model_component.py - - exit 0 -fi +# COMPONENT_NAME should be the name of the folder in components folder +export COMPONENT_NAME="$(basename "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")" -DATA_SCIENCE_PROJECT_NAMESPACE=$(oc project --short) +echo "Compiling test pipeline for COMPONENT_NAME ${COMPONENT_NAME}" -# If DATA_SCIENCE_PROJECT_NAMESPACE is empty print error and exit -if [ -z "$DATA_SCIENCE_PROJECT_NAMESPACE" ]; then - echo "Error: No namespace found. Please set the namespace in bootstrap/.env file." - exit 1 +# Export variables needed while compiling the pipeline +export BASE_IMAGE REGISTRY TAG +export PYTHONPATH=$(pwd)/src:$(dirname "$(pwd)") + +COMPILED_COMPONENT=$(pwd)/src/component_metadata/${COMPONENT_NAME}.yaml + +# Check if COMPILED_COMPONENT file exists +if [ -f "${COMPILED_COMPONENT}" ]; then + echo "COMPILED_COMPONENT ${COMPILED_COMPONENT} found." +else + echo "COMPILED_COMPONENT ${COMPILED_COMPONENT} not found." + echo "Please go to $(dirname "$(pwd)") and run $ ./build-component.sh ${COMPONENT_NAME}" + exit 1 fi TOKEN=$(oc whoami -t) @@ -25,7 +32,17 @@ TOKEN=$(oc whoami -t) if [ -z "$TOKEN" ]; then echo "Error: No token found. Please login to OpenShift using 'oc login' command." echo "Compile only mode." - + + python pipeline.py + + exit 1 +fi + +DATA_SCIENCE_PROJECT_NAMESPACE=$(oc project --short) + +# If DATA_SCIENCE_PROJECT_NAMESPACE is empty print error and exit +if [ -z "$DATA_SCIENCE_PROJECT_NAMESPACE" ]; then + echo "Error: No namespace found. Please set the namespace in bootstrap/.env file." exit 1 fi @@ -39,7 +56,7 @@ if [ -z "$DSPA_HOST" ]; then exit 1 fi -python register_model_component.py $TOKEN $DSPA_HOST +python pipeline.py $TOKEN $DSPA_HOST diff --git a/components/register_model/model-registries.yaml b/components/register_model/model-registries.yaml deleted file mode 100644 index 68001d5..0000000 --- a/components/register_model/model-registries.yaml +++ /dev/null @@ -1,197 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: modelregistry.opendatahub.io/v1alpha1 - kind: ModelRegistry - metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"modelregistry.opendatahub.io/v1alpha1","kind":"ModelRegistry","metadata":{"annotations":{"openshift.io/description":"","openshift.io/display-name":"model-registry-dev"},"labels":{"app.kubernetes.io/instance":"model-registry-dev","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"model-registry","app.kubernetes.io/version":"0.1.0","helm.sh/chart":"model-registry-0.1.0"},"name":"model-registry-dev","namespace":"rhoai-model-registries"},"spec":{"grpc":{"image":"registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8@sha256:927a88bade78e121d84e4d072f07a203fb00173af3615e00ce712d45329dde2d","port":9090},"istio":{"audiences":["https://kubernetes.default.svc"],"authConfigLabels":{"security.opendatahub.io/authorization-group":"default"},"authProvider":"redhat-ods-applications-auth-provider","gateway":{"grpc":{"gatewayRoute":"enabled","port":443,"tls":{"credentialName":"default-modelregistry-cert","mode":"SIMPLE"}},"istioIngress":"ingressgateway","rest":{"gatewayRoute":"enabled","port":443,"tls":{"credentialName":"default-modelregistry-cert","mode":"SIMPLE"}}},"tlsMode":"ISTIO_MUTUAL"},"mysql":{"database":"metadb","host":"model-registry-dev-db.rhoai-model-registries.svc.cluster.local","passwordSecret":{"key":"database-password","name":"model-registry-dev-db"},"port":3306,"skipDBCreation":false,"username":"root"},"rest":{"image":"quay.io/opendatahub/model-registry:v0.2.10","port":8080,"resources":{"limits":{"cpu":"100m","memory":"256Mi"},"requests":{"cpu":"100m","memory":"256Mi"}},"serviceRoute":"disabled"}}} - openshift.io/description: "" - openshift.io/display-name: model-registry-dev - creationTimestamp: "2025-01-31T10:15:36Z" - finalizers: - - modelregistry.opendatahub.io/finalizer - generation: 2 - labels: - app.kubernetes.io/instance: model-registry-dev - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: model-registry - app.kubernetes.io/version: 0.1.0 - helm.sh/chart: model-registry-0.1.0 - name: model-registry-dev - namespace: rhoai-model-registries - resourceVersion: "5855547" - uid: 0b6eebac-cdf9-4521-bdf9-45fc2f81b7a3 - spec: - grpc: - image: registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8@sha256:927a88bade78e121d84e4d072f07a203fb00173af3615e00ce712d45329dde2d - port: 9090 - istio: - audiences: - - https://kubernetes.default.svc - authConfigLabels: - security.opendatahub.io/authorization-group: default - authProvider: redhat-ods-applications-auth-provider - gateway: - grpc: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - istioIngress: ingressgateway - rest: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - tlsMode: ISTIO_MUTUAL - mysql: - database: metadb - host: model-registry-dev-db.rhoai-model-registries.svc.cluster.local - passwordSecret: - key: database-password - name: model-registry-dev-db - port: 3306 - skipDBCreation: false - username: root - rest: - image: quay.io/opendatahub/model-registry:v0.2.10 - port: 8080 - resources: - limits: - cpu: 100m - memory: 256Mi - requests: - cpu: 100m - memory: 256Mi - serviceRoute: disabled - status: - conditions: - - lastTransitionTime: "2025-01-31T10:16:21Z" - message: Deployment was successfully created - reason: CreatedDeployment - status: "True" - type: Progressing - - lastTransitionTime: "2025-02-07T16:34:46Z" - message: 'unexpected reconcile error: Internal error occurred: failed calling - webhook "rev.validation.istio.io": failed to call webhook: Post "https://istiod-data-science-smcp.istio-system.svc:443/validate?timeout=10s": - dial tcp 10.130.2.56:15017: connect: connection refused' - reason: DeploymentUnavailable - status: "False" - type: Available - - lastTransitionTime: "2025-01-31T10:16:37Z" - message: Istio resources are available - reason: ResourcesAvailable - status: "True" - type: IstioAvailable - - lastTransitionTime: "2025-01-31T10:16:37Z" - message: Istio Gateway resources are available - reason: ResourcesAvailable - status: "True" - type: GatewayAvailable - hosts: - - model-registry-dev.rhoai-model-registries.svc.cluster.local - - model-registry-dev.rhoai-model-registries - - model-registry-dev - hostsStr: model-registry-dev.rhoai-model-registries.svc.cluster.local,model-registry-dev.rhoai-model-registries,model-registry-dev - specDefaults: '{"grpc":{"resources":{"limits":{"cpu":"100m","memory":"256Mi"},"requests":{"cpu":"100m","memory":"256Mi"}}},"istio":{"gateway":{"domain":"apps.cluster-cwxrr.cwxrr.sandbox1533.opentlc.com"}}}' -- apiVersion: modelregistry.opendatahub.io/v1alpha1 - kind: ModelRegistry - metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"modelregistry.opendatahub.io/v1alpha1","kind":"ModelRegistry","metadata":{"annotations":{"openshift.io/description":"","openshift.io/display-name":"model-registry-users"},"labels":{"app.kubernetes.io/instance":"model-registry-users","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"model-registry","app.kubernetes.io/version":"0.1.0","helm.sh/chart":"model-registry-0.1.0"},"name":"model-registry-users","namespace":"rhoai-model-registries"},"spec":{"grpc":{"image":"registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8@sha256:927a88bade78e121d84e4d072f07a203fb00173af3615e00ce712d45329dde2d","port":9090},"istio":{"audiences":["https://kubernetes.default.svc"],"authConfigLabels":{"security.opendatahub.io/authorization-group":"default"},"authProvider":"redhat-ods-applications-auth-provider","gateway":{"grpc":{"gatewayRoute":"enabled","port":443,"tls":{"credentialName":"default-modelregistry-cert","mode":"SIMPLE"}},"istioIngress":"ingressgateway","rest":{"gatewayRoute":"enabled","port":443,"tls":{"credentialName":"default-modelregistry-cert","mode":"SIMPLE"}}},"tlsMode":"ISTIO_MUTUAL"},"mysql":{"database":"metadb","host":"model-registry-users-db.rhoai-model-registries.svc.cluster.local","passwordSecret":{"key":"database-password","name":"model-registry-users-db"},"port":3306,"skipDBCreation":false,"username":"root"},"rest":{"image":"quay.io/opendatahub/model-registry:v0.2.10","port":8080,"resources":{"limits":{"cpu":"100m","memory":"256Mi"},"requests":{"cpu":"100m","memory":"256Mi"}},"serviceRoute":"disabled"}}} - openshift.io/description: "" - openshift.io/display-name: model-registry-users - creationTimestamp: "2025-01-30T17:55:05Z" - finalizers: - - modelregistry.opendatahub.io/finalizer - generation: 3 - labels: - app.kubernetes.io/instance: model-registry-users - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: model-registry - app.kubernetes.io/version: 0.1.0 - helm.sh/chart: model-registry-0.1.0 - name: model-registry-users - namespace: rhoai-model-registries - resourceVersion: "5878675" - uid: 213712b1-3892-4338-a914-46ec9422809a - spec: - grpc: - image: registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8@sha256:927a88bade78e121d84e4d072f07a203fb00173af3615e00ce712d45329dde2d - port: 9090 - istio: - audiences: - - https://kubernetes.default.svc - authConfigLabels: - security.opendatahub.io/authorization-group: default - authProvider: redhat-ods-applications-auth-provider - gateway: - grpc: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - istioIngress: ingressgateway - rest: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - tlsMode: ISTIO_MUTUAL - mysql: - database: metadb - host: model-registry-users-db.rhoai-model-registries.svc.cluster.local - passwordSecret: - key: database-password - name: model-registry-users-db - port: 3306 - skipDBCreation: false - username: root - rest: - image: quay.io/opendatahub/model-registry:v0.2.10 - port: 8080 - resources: - limits: - cpu: 100m - memory: 256Mi - requests: - cpu: 100m - memory: 256Mi - serviceRoute: disabled - status: - conditions: - - lastTransitionTime: "2025-02-07T16:41:24Z" - message: Updating deployment - reason: UpdatingDeployment - status: "False" - type: Progressing - - lastTransitionTime: "2025-02-07T16:41:24Z" - message: Istio resources are unavailable - reason: ResourcesUnavailable - status: "False" - type: Available - - lastTransitionTime: "2025-02-07T16:41:24Z" - message: 'Istio AuthConfig is not ready: {reason: Reconciling, message: }' - reason: ResourcesUnavailable - status: "False" - type: IstioAvailable - - lastTransitionTime: "2025-01-30T18:12:11Z" - message: Istio Gateway resources are available - reason: ResourcesAvailable - status: "True" - type: GatewayAvailable - hosts: - - model-registry-users.rhoai-model-registries.svc.cluster.local - - model-registry-users.rhoai-model-registries - - model-registry-users - hostsStr: model-registry-users.rhoai-model-registries.svc.cluster.local,model-registry-users.rhoai-model-registries,model-registry-users - specDefaults: '{"grpc":{"resources":{"limits":{"cpu":"100m","memory":"256Mi"},"requests":{"cpu":"100m","memory":"256Mi"}}},"istio":{"gateway":{"domain":"apps.cluster-cwxrr.cwxrr.sandbox1533.opentlc.com"}}}' -kind: List -metadata: - resourceVersion: "" diff --git a/components/register_model/pipeline.py b/components/register_model/pipeline.py new file mode 100644 index 0000000..0f9e623 --- /dev/null +++ b/components/register_model/pipeline.py @@ -0,0 +1,78 @@ +# DOCS: https://www.kubeflow.org/docs/components/pipelines/user-guides/components/ + +import os + +from kfp import dsl +from kfp.dsl import Output, Metrics + +from src.register_model import register_model + +COMPONENT_NAME=os.getenv("COMPONENT_NAME") +print(f"COMPONENT_NAME: {COMPONENT_NAME}") + +# Dummy component that generates metrics +@dsl.component( + base_image="python:3.9", + packages_to_install=["numpy==1.21.4"] +) +def generate_metrics(results_output_metrics: Output[Metrics]): + results_output_metrics.log_metric("accuracy", 0.99) + results_output_metrics.log_metric("precision", 0.95) + +# This pipeline will download training dataset, download the model, test the model and if it performs well, +# upload the model to another S3 bucket. +@dsl.pipeline(name="register-model-test-pl") +def pipeline( + model_registry_name: str = "model-registry-dev", + model_registry_namespace: str = "rhoai-model-registries", + model_name: str = "model_name", + model_uri: str = "oci://model_uri", + model_version: str = "0.1.0", + model_description: str = "model_description", + model_format_name: str = "onnx", + model_format_version: str = "1", + author: str = "author", + owner: str = "owner", + ): + + # Generate metrics + generate_metrics_task = generate_metrics() # type: ignore + + # Generate labels + labels = """{ + "finance": "", + "fraud": "" + }""" + + # Register model + register_model_task = register_model( + model_registry_name=model_registry_name, + model_registry_namespace=model_registry_namespace, + model_name=model_name, + model_uri=model_uri, + model_version=model_version, + model_description=model_description, + model_format_name=model_format_name, + model_format_version=model_format_version, + author=author, + owner=owner, + labels=labels + ).set_caching_options(False) + + # register_model_task.set_service_account_name("register-model-sa") + +if __name__ == '__main__': + from shared.kubeflow import compile_and_upsert_pipeline + + import os + + pipeline_package_path = __file__.replace('.py', '.yaml') + + # Pipeline name + pipeline_name=f"{COMPONENT_NAME}_pl" + + compile_and_upsert_pipeline( + pipeline_func=pipeline, + pipeline_package_path=pipeline_package_path, + pipeline_name=pipeline_name + ) \ No newline at end of file diff --git a/components/register_model/push.sh b/components/register_model/push.sh deleted file mode 100755 index a2f070f..0000000 --- a/components/register_model/push.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -. .env - -podman tag localhost/${COMPONENT_NAME}:latest quay.io/atarazana/${COMPONENT_NAME}:latest -podman push quay.io/atarazana/${COMPONENT_NAME}:latest diff --git a/components/register_model/pyproject.toml b/components/register_model/pyproject.toml index bb35937..c4f4724 100644 --- a/components/register_model/pyproject.toml +++ b/components/register_model/pyproject.toml @@ -10,5 +10,5 @@ dependencies = [ "kfp[kubernetes]==2.8.0", "kubernetes==23.6.0", "load-dotenv==0.1.0", - "model-registry==0.2.13", + "model-registry==0.2.21", ] diff --git a/components/register_model/register_model_component.py b/components/register_model/register_model_component.py deleted file mode 100644 index 04eeade..0000000 --- a/components/register_model/register_model_component.py +++ /dev/null @@ -1,199 +0,0 @@ -# DOCS: https://www.kubeflow.org/docs/components/pipelines/user-guides/components/ - -import os -import sys -import time - -from kubernetes import client, config - -import kfp - -from kfp import compiler -from kfp import dsl -from kfp.dsl import Output, Metrics - -from src.register_model import register_model - -# Dummy component that generates metrics -@dsl.component( - base_image="python:3.9", - packages_to_install=["numpy==1.21.4"] -) -def generate_metrics(results_output_metrics: Output[Metrics]): - results_output_metrics.log_metric("accuracy", 0.99) - results_output_metrics.log_metric("precision", 0.95) - -# This pipeline will download training dataset, download the model, test the model and if it performs well, -# upload the model to another S3 bucket. -@dsl.pipeline(name="register-model-test-pl") -def pipeline( - model_registry_name: str = "model-registry-dev", - istio_system_namespace: str = "istio-system", - model_name: str = "model_name", - model_uri: str = "oci://model_uri", - model_version: str = "0.1.0", - model_description: str = "model_description", - model_format_name: str = "onnx", - model_format_version: str = "1", - author: str = "author", - owner: str = "owner", - ): - - # Generate metrics - generate_metrics_task = generate_metrics() - - # Generate labels - labels = { - "finance": "", - "fraud": "" - } - - # Register model - register_model_task = register_model( - model_registry_name=model_registry_name, - istio_system_namespace=istio_system_namespace, - model_name=model_name, - model_uri=model_uri, - model_version=model_version, - model_description=model_description, - model_format_name=model_format_name, - model_format_version=model_format_version, - author=author, - owner=owner, - labels=labels, - input_metrics=generate_metrics_task.outputs["results_output_metrics"], - ).set_caching_options(False) - - # register_model_task.set_service_account_name("register-model-sa") - -if __name__ == '__main__': - import time - import sys - import os - - from kfp import compiler - - from kubernetes import client, config - - def get_pipeline_by_name(client: kfp.Client, pipeline_name: str): - import json - - # Define filter predicates - filter_spec = json.dumps({ - "predicates": [{ - "key": "display_name", - "operation": "EQUALS", - "stringValue": pipeline_name, - }] - }) - - # List pipelines with the specified filter - pipelines = client.list_pipelines(filter=filter_spec) - - if not pipelines.pipelines: - return None - for pipeline in pipelines.pipelines: - if pipeline.display_name == pipeline_name: - return pipeline - - return None - - # Get the service account token or return None - def get_token(): - try: - with open("/var/run/secrets/kubernetes.io/serviceaccount/token", "r") as f: - return f.read().strip() - except Exception as e: - print(f"Error: {e}") - return None - - # Get the route host for the specified route name in the specified namespace - def get_route_host(route_name: str): - # Load in-cluster Kubernetes configuration but if it fails, load local configuration - try: - config.load_incluster_config() - except config.config_exception.ConfigException: - config.load_kube_config() - - # Get the current namespace - with open("/var/run/secrets/kubernetes.io/serviceaccount/namespace", "r") as f: - namespace = f.read().strip() - - # Create Kubernetes API client - api_instance = client.CustomObjectsApi() - - try: - # Retrieve the route object - route = api_instance.get_namespaced_custom_object( - group="route.openshift.io", - version="v1", - namespace=namespace, - plural="routes", - name=route_name - ) - - # Extract spec.host field - route_host = route['spec']['host'] - return route_host - - except Exception as e: - print(f"Error: {e}") - return None - - pipeline_package_path = __file__.replace('.py', '.yaml') - - compiler.Compiler().compile( - pipeline_func=pipeline, - package_path=pipeline_package_path - ) - - # Take token and kfp_endpoint as optional command-line arguments - token = sys.argv[1] if len(sys.argv) > 1 else None - kfp_endpoint = sys.argv[2] if len(sys.argv) > 2 else None - - if not token: - print("Token endpoint not provided finding it automatically.") - token = get_token() - - if not kfp_endpoint: - print("KFP endpoint not provided finding it automatically.") - kfp_endpoint = get_route_host(route_name="ds-pipeline-dspa") - - # Pipeline name - pipeline_name = os.path.basename(__file__).replace('.py', '') - - # If both kfp_endpoint and token are provided, upload the pipeline - if kfp_endpoint and token: - client = kfp.Client(host=kfp_endpoint, existing_token=token) - - # If endpoint doesn't have a protocol (http or https), add https - if not kfp_endpoint.startswith("http"): - kfp_endpoint = f"https://{kfp_endpoint}" - - try: - # Get the pipeline by name - print(f"Pipeline name: {pipeline_name}") - existing_pipeline = get_pipeline_by_name(client, pipeline_name) - if existing_pipeline: - print(f"Pipeline {existing_pipeline.pipeline_id} already exists. Uploading a new version.") - # Upload a new version of the pipeline with a version name equal to the pipeline package path plus a timestamp - pipeline_version_name=f"{pipeline_name}-{int(time.time())}" - client.upload_pipeline_version( - pipeline_package_path=pipeline_package_path, - pipeline_id=existing_pipeline.pipeline_id, - pipeline_version_name=pipeline_version_name - ) - print(f"Pipeline version uploaded successfully to {kfp_endpoint}") - else: - print(f"Pipeline {pipeline_name} does not exist. Uploading a new pipeline.") - print(f"Pipeline package path: {pipeline_package_path}") - # Upload the compiled pipeline - client.upload_pipeline( - pipeline_package_path=pipeline_package_path, - pipeline_name=pipeline_name - ) - print(f"Pipeline uploaded successfully to {kfp_endpoint}") - except Exception as e: - print(f"Failed to upload the pipeline: {e}") - else: - print("KFP endpoint or token not provided. Skipping pipeline upload.") \ No newline at end of file diff --git a/components/register_model/register_model_component.yaml b/components/register_model/register_model_component.yaml deleted file mode 100644 index 30d9fc7..0000000 --- a/components/register_model/register_model_component.yaml +++ /dev/null @@ -1,219 +0,0 @@ -# PIPELINE DEFINITION -# Name: register-model-test-pl -# Inputs: -# author: str [Default: 'author'] -# istio_system_namespace: str [Default: 'istio-system'] -# model_description: str [Default: 'model_description'] -# model_format_name: str [Default: 'onnx'] -# model_format_version: str [Default: '1'] -# model_name: str [Default: 'model_name'] -# model_registry_name: str [Default: 'model-registry-dev'] -# model_uri: str [Default: 'oci://model_uri'] -# model_version: str [Default: '0.1.0'] -# owner: str [Default: 'owner'] -# Outputs: -# generate-metrics-results_output_metrics: system.Metrics -components: - comp-generate-metrics: - executorLabel: exec-generate-metrics - outputDefinitions: - artifacts: - results_output_metrics: - artifactType: - schemaTitle: system.Metrics - schemaVersion: 0.0.1 - comp-register-model: - executorLabel: exec-register-model - inputDefinitions: - artifacts: - input_metrics: - artifactType: - schemaTitle: system.Metrics - schemaVersion: 0.0.1 - parameters: - author: - parameterType: STRING - istio_system_namespace: - parameterType: STRING - labels: - parameterType: STRUCT - model_description: - parameterType: STRING - model_format_name: - parameterType: STRING - model_format_version: - parameterType: STRING - model_name: - parameterType: STRING - model_registry_name: - parameterType: STRING - model_uri: - parameterType: STRING - model_version: - parameterType: STRING - owner: - parameterType: STRING - outputDefinitions: - parameters: - output_model_id: - parameterType: STRING -deploymentSpec: - executors: - exec-generate-metrics: - container: - args: - - --executor_input - - '{{$}}' - - --function_to_execute - - generate_metrics - command: - - sh - - -c - - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ - \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ - \ python3 -m pip install --quiet --no-warn-script-location 'kfp==2.8.0'\ - \ '--no-deps' 'typing-extensions>=3.7.4,<5; python_version<\"3.9\"' &&\ - \ python3 -m pip install --quiet --no-warn-script-location 'numpy==1.21.4'\ - \ && \"$0\" \"$@\"\n" - - sh - - -ec - - 'program_path=$(mktemp -d) - - - printf "%s" "$0" > "$program_path/ephemeral_component.py" - - _KFP_RUNTIME=true python3 -m kfp.dsl.executor_main --component_module_path "$program_path/ephemeral_component.py" "$@" - - ' - - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\ - \ *\n\ndef generate_metrics(results_output_metrics: Output[Metrics]):\n\ - \ results_output_metrics.log_metric(\"accuracy\", 0.99)\n results_output_metrics.log_metric(\"\ - precision\", 0.95)\n\n" - image: python:3.9 - exec-register-model: - container: - args: - - --executor_input - - '{{$}}' - - --function_to_execute - - register_model - command: - - sh - - -c - - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ - \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ - \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.2.13'\ - \ 'kubernetes==23.6.0' 'load_dotenv==0.1.0' 'botocore==1.35.54' 'boto3==1.35.54'\ - \ && \"$0\" \"$@\"\n" - - python3 - - -m - - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:latest -pipelineInfo: - name: register-model-test-pl -root: - dag: - outputs: - artifacts: - generate-metrics-results_output_metrics: - artifactSelectors: - - outputArtifactKey: results_output_metrics - producerSubtask: generate-metrics - tasks: - generate-metrics: - cachingOptions: - enableCache: true - componentRef: - name: comp-generate-metrics - taskInfo: - name: generate-metrics - register-model: - cachingOptions: {} - componentRef: - name: comp-register-model - dependentTasks: - - generate-metrics - inputs: - artifacts: - input_metrics: - taskOutputArtifact: - outputArtifactKey: results_output_metrics - producerTask: generate-metrics - parameters: - author: - componentInputParameter: author - istio_system_namespace: - componentInputParameter: istio_system_namespace - labels: - runtimeValue: - constant: - finance: '' - fraud: '' - model_description: - componentInputParameter: model_description - model_format_name: - componentInputParameter: model_format_name - model_format_version: - componentInputParameter: model_format_version - model_name: - componentInputParameter: model_name - model_registry_name: - componentInputParameter: model_registry_name - model_uri: - componentInputParameter: model_uri - model_version: - componentInputParameter: model_version - owner: - componentInputParameter: owner - taskInfo: - name: register-model - inputDefinitions: - parameters: - author: - defaultValue: author - isOptional: true - parameterType: STRING - istio_system_namespace: - defaultValue: istio-system - isOptional: true - parameterType: STRING - model_description: - defaultValue: model_description - isOptional: true - parameterType: STRING - model_format_name: - defaultValue: onnx - isOptional: true - parameterType: STRING - model_format_version: - defaultValue: '1' - isOptional: true - parameterType: STRING - model_name: - defaultValue: model_name - isOptional: true - parameterType: STRING - model_registry_name: - defaultValue: model-registry-dev - isOptional: true - parameterType: STRING - model_uri: - defaultValue: oci://model_uri - isOptional: true - parameterType: STRING - model_version: - defaultValue: 0.1.0 - isOptional: true - parameterType: STRING - owner: - defaultValue: owner - isOptional: true - parameterType: STRING - outputDefinitions: - artifacts: - generate-metrics-results_output_metrics: - artifactType: - schemaTitle: system.Metrics - schemaVersion: 0.0.1 -schemaVersion: 2.1.0 -sdkVersion: kfp-2.8.0 diff --git a/components/register_model/requirements.txt b/components/register_model/requirements.txt index e3db5aa..e9da19d 100644 --- a/components/register_model/requirements.txt +++ b/components/register_model/requirements.txt @@ -1,5 +1,5 @@ kfp[kubernetes]==2.8.0 -model_registry==0.2.13 +model_registry==0.2.21 boto3==1.35.54 botocore==1.35.54 kubernetes==23.6.0 diff --git a/components/register_model/run.sh b/components/register_model/run.sh deleted file mode 100755 index e7cc58e..0000000 --- a/components/register_model/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -. .env - -# podman run -it --rm localhost/${COMPONENT_NAME}:latest $@ -podman run -it --rm --entrypoint bash localhost/${COMPONENT_NAME}:latest diff --git a/components/register_model/src/__pycache__/register_model.cpython-312.pyc b/components/register_model/src/__pycache__/register_model.cpython-312.pyc deleted file mode 100644 index 0b25a5779274fd47d57f3271898ec890390252b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4837 zcmb6cTWlN0agV&?{yDILreE!6ks?ii{+ucSVlOFRpbd)t(Xj)!Mn5`x)R9sW z7d469nVp@PotfR8+53~j!6Wz`_I$cf^da;&I?#WiUF6}E0ihd6KmwCSu_|O@j5apJ z3;+#jV}^~f44pHkxr`}h%9vy3j3s8#Xe`WIV^$64(tL)G@eDE`%-`KzfXklp2LF<6kEx7S6vn$)Ve>~qT9QZk_$351BgF@HkZiL7Q z+`ROoz1Hr^9~2JN{B8wZ?9$NpxpaL?!{497O}O=5x2}UhE6fVh)ALWtIMu_bmSirI zPo**GF{<1|HeZlb^CXr?Dk-Y`bU^~b`Gm9xoJK)R1F)rY2_Y`zB%HmX@@G!ZM&lEc zr^lkjV17kf%w>lLBLf3{Vmg)SyHrT0MZAJl>(uGV=~X;Q2%$Evc57=-9;U zg_*hHKq`}1z{IIE);7 zoP!~MDJSKUIf4NH%1X;k+?#P=@Brk(AVqD6_Q&~|;q|>T* z|Dy41B7@Zc_?pVa#T8M)8I2@@ELQm{v&Lhs;sugY9aZ!SCSod=RXx?AfW;(99VFo0rrWgTy8mwiE2tGF5$GOx^miPSK}E^32Ng$!mcz-BprJW znGJAyO&-3^YDtQLWP~!zsv~1qb!LpKE=W2IBqcV(t-5K_kzF#98T~k}dSp+@Ce<_w ztbTFcWh9rrj=;&r*(aHIBWO^E&li zCWTfTWS)%5{F1kBosQ|3l^nMs$*)s?DE-PcovS?P`hjGu>l#IGKp}Y@((=rkrl}e|66w5yY5RGQz&V81EN~f;+6Cggk+!Y-TQ`XUKaeL>+IPfyR4;C zolDzkx9kxdu;UKh%6m>drLOvA|5Cf|dmYLK*&jY?94#!#&qsYju7#@C<&y zxvcr&Bg{3c?3I0By8~=*)MC^q2jXshWmqi`ubn8ctxKP&Lpf0Q4mb|gXLJm#XKN>$ zm3nG)o8Z>zC(vq>+_ZE=pQ}ST@Iytbz9tlR`0IKYv`4@F|I*JsoBkEli6nTGRDVm& zI#!1V5V3dOTBvzB(ZNT4}zOa+h&db!Dohil$p3m6X&LI#*45dXkUhtdP&8vJw<8$0V&5 zGrN_h*r5%>I%int3}LO=nr>DYDLQ~m=NRfvso)8jJVkoRSs~+mrvd2K0Ae1U! z5P_scvd5~jwB~3Ngk~DmNb8PSuNt;JwT95AB59;d7T5r76_r`;X;is_luC=Fjn32S zO~RDPsd- zTxN4Fqh#OSo?EFPG-5bscuc`X!-FaS;!h2486MG5!k{e|-*UdCSl$BF?uODh7-n&9 z9K6wcz4wDig*90(Fn{+4Z^W+0Zkx9JhpxU-ZaeVH^oQwN*>4czIC!1kFmAkB4tH%> zZhC*=cwhut#f}DF{B7hnk*#BAc3dOBI(vKMj(@}W!R$@{`?2dT#WhkI-*k;={#`x0 z@%F}&!aujocEHl^kPISxETyu(zAR+`b_W4~_uxNWQFg&o`2heJ09Z*!meua0c^*Ul=o zvC`bYO<#9S;~kH@1#<7(efB zA2%Dn2yo-=<}W(9@gru{5|3vRscbx6G{ONca*>rpCf#FD9r;uqr&C!RpD$#Ss(trO zAJ5b8pmx=e6Uk9}XAK0yy`9e!`T$nVfJNXFiNHe`5sr2y+L>u*flf8U7gLHrIx|8R zBJ@>5=+{57(@Fb<(=%hy3)OEawRv)SGa~3nzBAJorbnh{qWh>GN*&xsveqs;IZiFoaw&v|R)lz*28!k$z{~{a z)ATbXP?LbLXrDYC?&qXxrW_#kF?t9p5jg|h6U$4GY6@w5iu??Q^cz_$Ll67S zFkd3;m&gYF*Qn_qD6)wne?{JJO^7-07i9an1CFQDy&hYOt-rbU=FM};;pmp*l@edJ zJJ-*yon4<=o4Wbp9qX3;Sjk$pIo5~PhSpE5ow|8g>7G+!No7t@4&p7_e93aZp?RZO zX&F#l$4d75Eu9K#F1wpbu5wemf*Q;IHU;_04J``tz>)@6$@^aDolw~oEPF!bmLp2< zE6R~EB{*JgIdsRR96G54UnsY9D?KkO-KUk{nQ{xHuOX%DMJ4!BxurwtJg#({P=e1_ ztZeY)BeTU|s5D$;n67fLwPK{m{nqvhN0EvJd3+VChVsbmt=Kfwj(m+3hlV;)Q%l9A zp>B$LG_(P=v{k$s>O&59#jl|OWOr2>HMEIRgA{$xi~`}?#`oiu7H!yy+Pd!;Z^gd} z(cwdH&AN(YK&<_0@z2KK{ZQ9VsBbgWcL#rRaVs>eu+8^be`$P&^>4ENEw*uoZQo?u b%Yg%B|B(uZxbU~g$eAiu#5R){?C^g9AEwXe diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index 250ac8d..d5a9cd2 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -2,13 +2,13 @@ # Name: register-model # Inputs: # author: str -# istio_system_namespace: str # labels: str # model_description: str # model_format_name: str # model_format_version: str # model_name: str # model_registry_name: str +# model_registry_namespace: str # model_uri: str # model_version: str # owner: str @@ -22,8 +22,6 @@ components: parameters: author: parameterType: STRING - istio_system_namespace: - parameterType: STRING labels: parameterType: STRING model_description: @@ -36,6 +34,8 @@ components: parameterType: STRING model_registry_name: parameterType: STRING + model_registry_namespace: + parameterType: STRING model_uri: parameterType: STRING model_version: @@ -62,13 +62,13 @@ deploymentSpec: - -c - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ - \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.2.13'\ + \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.2.14'\ \ 'kubernetes==23.6.0' 'load_dotenv==0.1.0' 'botocore==1.35.54' 'boto3==1.35.54'\ \ && \"$0\" \"$@\"\n" - python3 - -m - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:latest + image: quay.io/atarazana/register_model:v1.0.2 pipelineInfo: name: register-model root: @@ -93,8 +93,6 @@ root: parameters: author: componentInputParameter: author - istio_system_namespace: - componentInputParameter: istio_system_namespace labels: componentInputParameter: labels model_description: @@ -107,6 +105,8 @@ root: componentInputParameter: model_name model_registry_name: componentInputParameter: model_registry_name + model_registry_namespace: + componentInputParameter: model_registry_namespace model_uri: componentInputParameter: model_uri model_version: @@ -119,8 +119,6 @@ root: parameters: author: parameterType: STRING - istio_system_namespace: - parameterType: STRING labels: parameterType: STRING model_description: @@ -133,6 +131,8 @@ root: parameterType: STRING model_registry_name: parameterType: STRING + model_registry_namespace: + parameterType: STRING model_uri: parameterType: STRING model_version: diff --git a/components/register_model/src/register_model.py b/components/register_model/src/register_model.py index aad15b5..bdf366c 100644 --- a/components/register_model/src/register_model.py +++ b/components/register_model/src/register_model.py @@ -1,42 +1,47 @@ import os import json -import re +import logging from kfp import compiler -from kfp.dsl import Input, Metrics, OutputPath +from kfp.dsl import Input, OutputPath from kfp import dsl +from shared.utils import get_model_registry_endpoint +from shared.kubeflow import get_token + +from model_registry import ModelRegistry + # Load environment variables with load_dotenv from load_dotenv import load_dotenv load_dotenv() # Set environment variables -BASE_IMAGE = os.environ.get("BASE_IMAGE", "python:3.11-slim-bullseye") -NAMESPACE = os.environ.get("NAMESPACE", "default") -REGISTRY = os.environ.get("REGISTRY", f"image-registry.openshift-image-registry.svc:5000/{NAMESPACE}") - -TARGET_IMAGE = f"{REGISTRY}/register_model:latest" - -MODEL_REGISTRY_PIP_VERSION="0.2.13" +NAMESPACE=os.environ.get("NAMESPACE", "default") +COMPONENT_NAME=os.getenv("COMPONENT_NAME", f"register_model") +BASE_IMAGE=os.getenv("BASE_IMAGE", "python:3.11-slim-bullseye") +REGISTRY=os.environ.get("REGISTRY", f"image-registry.openshift-image-registry.svc:5000/{NAMESPACE}") +TAG=os.environ.get("TAG", f"latest") +TARGET_IMAGE=f"{REGISTRY}/{COMPONENT_NAME}:{TAG}" + +MODEL_REGISTRY_PIP_VERSION="0.2.14" K8S_PIP_VERSION="23.6.0" LOAD_DOTENV_PIP_VERSION="0.1.0" BOTOCORE_PIP_VERSION="1.35.54" BOTO3_PIP_VERSION="1.35.54" -# This component registers a model in the model registry and returns the model ID -@dsl.component( - base_image=BASE_IMAGE, - target_image=TARGET_IMAGE, - packages_to_install=[f"model_registry=={MODEL_REGISTRY_PIP_VERSION}", - f"kubernetes=={K8S_PIP_VERSION}", - f"load_dotenv=={LOAD_DOTENV_PIP_VERSION}", - f"botocore=={BOTOCORE_PIP_VERSION}", - f"boto3=={BOTO3_PIP_VERSION}"], -) -def register_model( +# Allowed log levels +VALID_LOG_LEVELS = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} + +# Read from environment variable +LOG_LEVEL_STR = os.getenv("LOG_LEVEL", "WARNING").upper() + +# Create a logger for this module +_log = logging.getLogger(__name__) + +def _register_model( model_registry_name: str, # Name of the model registry - istio_system_namespace: str, # Namespace of the istio system namespace + model_registry_namespace: str, # Namespace of the model registries model_name: str, # Name of the model model_uri: str, # Path to the model file @@ -47,23 +52,49 @@ def register_model( author: str, # Author of the model owner: str, # Owner of the model labels: str, # Labels for the model as a json string - output_model_id: OutputPath(str), # type: ignore - output_model_version_id: OutputPath(str), # type: ignore -): - from utils import get_token, metrics_to_dict, get_model_registry_endpoint - - from model_registry import ModelRegistry +) -> tuple[str, str]: + """ + Register a model in the model registry. + Args: + model_registry_name (str): Name of the model registry + model_registry_namespace (str): Namespace of the model registries namespace + model_name (str): Name of the model + model_uri (str): Path to the model file + model_version (str): Version of the model + model_description (str): Description of the model + model_format_name (str): Model format name + model_format_version (str): Model format version + author (str): Author of the model + owner (str): Owner of the model + labels (str): Labels for the model as a json string + Returns: + tuple[str, str]: A tuple containing (model_id, model_version_id) + """ + # Log input parameters + _log.info(f"Model registry name: {model_registry_name}") + _log.info(f"Model registry namespace: {model_registry_namespace}") + _log.info(f"Model name: {model_name}") + _log.info(f"Model URI: {model_uri}") + _log.info(f"Model version: {model_version}") + _log.info(f"Model description: {model_description}") + _log.info(f"Model format name: {model_format_name}") + _log.info(f"Model format version: {model_format_version}") + _log.info(f"Author: {author}") + _log.info(f"Owner: {owner}") + _log.info(f"Labels: {labels}") # Get the model registry endpoint - model_registry_endpoint = get_model_registry_endpoint(model_registry_name, istio_system_namespace) + model_registry_endpoint = get_model_registry_endpoint(model_registry_name, model_registry_namespace) if model_registry_endpoint is None: + _log.error("Model registry endpoint not found.") raise ValueError("Model registry endpoint not found.") - # Print the model registry endpoint - print(f"Model registry endpoint: {model_registry_endpoint}") + # Log the model registry endpoint + _log.info(f"Model registry endpoint: {model_registry_endpoint}") # Check the uri and return a value error if it is not a valid uri and the protocol is s3, http, https or oci if not model_uri.startswith("s3://") and not model_uri.startswith("http://") and not model_uri.startswith("https://") and not model_uri.startswith("oci://"): + _log.error(f"Invalid model URI: {model_uri}. Supported protocols are s3, http, https, and oci.") raise ValueError("Invalid model URI. Supported protocols are s3, http, https, and oci.") # Generate metadata dict @@ -73,23 +104,27 @@ def register_model( if labels and labels.strip(): # If the labels is not a valid json string, return a value error try: - # Add labels to the metadata - labels = json.loads(labels) - for key, value in labels.items(): + # Parse labels from JSON string to dict + labels_dict = json.loads(labels) + for key, value in labels_dict.items(): metadata[key] = value - except json.JSONDecodeError: + _log.info(f"Parsed labels: {labels_dict}") + except json.JSONDecodeError as e: + _log.error(f"Invalid labels JSON: {labels}. Error: {e}") raise ValueError("Invalid labels. Labels must be a valid JSON string.") # Convert the metadata values to strings metadata = {key: str(value) for key, value in metadata.items()} - # Print the metadata - print(f"Metadata: {metadata}") + # Log the metadata + _log.info(f"Metadata: {metadata}") # Create the model registry object + _log.info("Creating model registry client...") registry = ModelRegistry(model_registry_endpoint, author="register_model", user_token=get_token()) # Register the model + _log.info(f"Registering model '{model_name}' version '{model_version}'...") model = registry.register_model( name=model_name, # model name author=author, # author of the model @@ -102,26 +137,94 @@ def register_model( metadata=metadata ) + # Check if the model was registered successfully + if model is None: + _log.error("Model registration failed.") + raise ValueError("Model registration failed. Please check the model registry endpoint and the model parameters.") + # Get the model ID + if model.id is None: + _log.error("Model ID is None after registration.") + raise ValueError("Model ID is None. Please check the model registration parameters.") + + _log.info(f"Model registered successfully with ID: {model.id}") + # Isolate the labels with no values tags = {key: value for key, value in metadata.items() if not value} - # Add the tags to the model as cusom properties + # Add the tags to the model as custom properties model.custom_properties = tags model.description = model_description # Save the model + _log.info("Updating model with custom properties...") registry.update(model) # Retrieve the model version - model_version = registry.get_model_version(model_name, model_version) + _log.info(f"Retrieving model version '{model_version}' for model '{model_name}'...") + model_version_obj = registry.get_model_version(model_name, model_version) + if model_version_obj is None: + _log.error(f"Model version {model_version} not found for model {model_name}.") + raise ValueError(f"Model version {model_version} not found for model {model_name}.") + # Check if the model version ID is None + if model_version_obj.id is None: + _log.error("Model version ID is None.") + raise ValueError("Model version ID is None. Please check the model registration parameters.") + + _log.info(f"Model version retrieved successfully with ID: {model_version_obj.id}") + + return model.id, model_version_obj.id + +# This component registers a model in the model registry and returns the model ID +@dsl.component( + base_image=BASE_IMAGE, + target_image=TARGET_IMAGE, + packages_to_install=[f"model_registry=={MODEL_REGISTRY_PIP_VERSION}", + f"kubernetes=={K8S_PIP_VERSION}", + f"load_dotenv=={LOAD_DOTENV_PIP_VERSION}", + f"botocore=={BOTOCORE_PIP_VERSION}", + f"boto3=={BOTO3_PIP_VERSION}"], +) +def register_model( + model_registry_name: str, # Name of the model registry + model_registry_namespace: str, # Namespace of the model registries + + model_name: str, # Name of the model + model_uri: str, # Path to the model file + model_version: str, # Version of the model + model_description: str, # Description of the model + model_format_name: str, # Model format name + model_format_version: str, # Model format version + author: str, # Author of the model + owner: str, # Owner of the model + labels: str, # Labels for the model as a json string + output_model_id: OutputPath(str), # type: ignore + output_model_version_id: OutputPath(str), # type: ignore +): + """ + Register a model in the model registry and save the model ID and version ID to output paths. + """ + # Call the private function to register the model + model_id, model_version_id = _register_model( + model_registry_name=model_registry_name, + model_registry_namespace=model_registry_namespace, + model_name=model_name, + model_uri=model_uri, + model_version=model_version, + model_description=model_description, + model_format_name=model_format_name, + model_format_version=model_format_version, + author=author, + owner=owner, + labels=labels, + ) # Save the model ID to the output path with open(output_model_id, 'w') as file: - file.write(model.id) + file.write(model_id) # Save the model version to the output path with open(output_model_version_id, 'w') as file: - file.write(model_version.id) + file.write(model_version_id) if __name__ == "__main__": @@ -131,4 +234,4 @@ def register_model( compiler.Compiler().compile( pipeline_func=register_model, package_path=component_package_path - ) + ) \ No newline at end of file diff --git a/components/register_model/src/runtime-requirements.txt b/components/register_model/src/runtime-requirements.txt index 03cbf70..7cf1277 100644 --- a/components/register_model/src/runtime-requirements.txt +++ b/components/register_model/src/runtime-requirements.txt @@ -3,4 +3,4 @@ boto3==1.35.54 botocore==1.35.54 kubernetes==23.6.0 load_dotenv==0.1.0 -model_registry==0.2.13 \ No newline at end of file +model_registry==0.2.14 \ No newline at end of file diff --git a/components/register_model/src/test.py b/components/register_model/src/test.py new file mode 100644 index 0000000..243254b --- /dev/null +++ b/components/register_model/src/test.py @@ -0,0 +1,163 @@ +import os +import logging +import time +import argparse +import json + +from register_model import _register_model + +# Allowed log levels +VALID_LOG_LEVELS = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} + +# Read from environment variable +LOG_LEVEL_STR = os.getenv("LOG_LEVEL", "WARNING").upper() + +# Create a logger for this module +_log = logging.getLogger(__name__) + +def main(): + # Validate and set level + if LOG_LEVEL_STR in VALID_LOG_LEVELS: + log_level = getattr(logging, LOG_LEVEL_STR) + else: + print(f"Invalid LOG_LEVEL '{LOG_LEVEL_STR}' - defaulting to WARNING") + log_level = logging.WARNING + + logging.basicConfig(level=log_level) + + # Parse command line arguments + parser = argparse.ArgumentParser(description="Test model registration with the model registry.") + + parser.add_argument( + '--model-registry-name', + required=True, + help='Name of the model registry' + ) + + parser.add_argument( + '--model-registry-namespace', + required=True, + help='Namespace of the model registry' + ) + + parser.add_argument( + '--model-name', + required=True, + help='Name of the model' + ) + + parser.add_argument( + '--model-uri', + required=True, + help='URI of the model' + ) + + parser.add_argument( + '--model-version', + required=True, + help='Version of the model' + ) + + parser.add_argument( + '--model-description', + required=False, + default='Test model registration', + help='Description of the model' + ) + + parser.add_argument( + '--model-format-name', + required=False, + default='pytorch', + help='Model format name' + ) + + parser.add_argument( + '--model-format-version', + required=False, + default='1', + help='Model format version' + ) + + parser.add_argument( + '--author', + required=False, + default='test-user', + help='Author of the model' + ) + + parser.add_argument( + '--owner', + required=False, + default='test-owner', + help='Owner of the model' + ) + + parser.add_argument( + '--labels', + required=False, + default='{}', + help='Labels for the model as a JSON string' + ) + + args = parser.parse_args() + + print(f"Model registry name: {args.model_registry_name}") + print(f"Istio system namespace: {args.model_registry_namespace}") + print(f"Model name: {args.model_name}") + print(f"Model URI: {args.model_uri}") + print(f"Model version: {args.model_version}") + print(f"Model description: {args.model_description}") + print(f"Model format name: {args.model_format_name}") + print(f"Model format version: {args.model_format_version}") + print(f"Author: {args.author}") + print(f"Owner: {args.owner}") + print(f"Labels: {args.labels}") + + # Start the timer + start_time = time.time() + + try: + # Register the model + model_id, model_version_id = _register_model( + model_registry_name=args.model_registry_name, + model_registry_namespace=args.model_registry_namespace, + model_name=args.model_name, + model_uri=args.model_uri, + model_version=args.model_version, + model_description=args.model_description, + model_format_name=args.model_format_name, + model_format_version=args.model_format_version, + author=args.author, + owner=args.owner, + labels=args.labels + ) + + results = json.dumps({ + "model_id": model_id, + "model_version_id": model_version_id, + "success": True + }) + + # Log the results + _log.info(f"Registration results: {results}") + print(f"Model registered successfully!") + print(f"Model ID: {model_id}") + print(f"Model Version ID: {model_version_id}") + + except Exception as e: + _log.error(f"Model registration failed: {e}") + print(f"Model registration failed: {e}") + results = json.dumps({ + "success": False, + "error": str(e) + }) + + # Stop the timer + end_time = time.time() - start_time + + _log.info(f"Model registration completed in {end_time:.2f} seconds.") + print(f"Model registration completed in {end_time:.2f} seconds.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/components/register_model/src/test.sh b/components/register_model/src/test.sh new file mode 100755 index 0000000..faead18 --- /dev/null +++ b/components/register_model/src/test.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Set PYTHONPATH to the components directory (parent of both shared and register_model) +export PYTHONPATH=$(cd "$(dirname "$0")"/../../ && pwd) + +# Set default environment variables for model registration +export MODEL_REGISTRY_NAME=${MODEL_REGISTRY_NAME:-"model-registry"} +export ISTIO_SYSTEM_NAMESPACE=${ISTIO_SYSTEM_NAMESPACE:-"istio-system"} + +# Get token using `oc whoami -t` +export TOKEN=$(oc whoami -t) + +# Write the token to a file .token +echo $TOKEN > .token + +# Run the test script with DEBUG log level with all the arguments +TOKEN_PATH=$(pwd)/.token LOG_LEVEL=DEBUG python test.py $@ + +# Clean up the token file +rm -f .token \ No newline at end of file diff --git a/components/register_model/src/utils.py b/components/register_model/src/utils.py deleted file mode 100644 index 31f8bb7..0000000 --- a/components/register_model/src/utils.py +++ /dev/null @@ -1,125 +0,0 @@ -import os -import json -import re - -from kubernetes import client as k8s_cli, config as k8s_conf - -from kfp.dsl import Input, Metrics - -# Get token path from environment or default to kubernetes token location -TOKEN_PATH = os.environ.get("TOKEN_PATH", "/var/run/secrets/kubernetes.io/serviceaccount/token") - -# Get the service account token or return None -def get_token(): - try: - with open(TOKEN_PATH, "r") as f: - return f.read().strip() - except Exception as e: - print(f"Error: {e}") - return None - -# Function that gets the model registry endpoint using a route object -def get_model_registry_endpoint(model_registry_name: str, - istio_system_namespace: str) -> str: - # Load in-cluster Kubernetes configuration but if it fails, load local configuration - try: - k8s_conf.load_incluster_config() - except k8s_conf.config_exception.ConfigException: - k8s_conf.load_kube_config() - - # Create Kubernetes API client - api_instance = k8s_cli.CustomObjectsApi() - - try: - # Retrieve the route object - routes = api_instance.list_namespaced_custom_object( - group="route.openshift.io", - version="v1", - namespace=istio_system_namespace, - plural="routes", - label_selector=f"app.kubernetes.io/instance={model_registry_name}" - ) - - # Extract spec.host fields - route_hosts = [route['spec']['host'] for route in routes['items']] - - # Return the route host only if it contains "-rest" else return None - for route_host in route_hosts: - if "-rest" in route_host: - return f'https://{route_host}' - return None - - except Exception as e: - print(f"Error: {e}") - return None - -# Get the route host for the specified route name in the specified namespace -def get_route_host(route_name: str): - # Load in-cluster Kubernetes configuration but if it fails, load local configuration - try: - k8s_conf.load_incluster_config() - except k8s_conf.config_exception.ConfigException: - k8s_conf.load_kube_config() - - # Get token path from environment or default to kubernetes token location - NAMESPACE_PATH = os.environ.get("NAMESPACE_PATH", "/var/run/secrets/kubernetes.io/serviceaccount/namespace") - - # Get the current namespace - with open(NAMESPACE_PATH, "r") as f: - namespace = f.read().strip() - - print(f"namespace: {namespace}") - - # Create Kubernetes API client - api_instance = k8s_cli.CustomObjectsApi() - - try: - # Retrieve the route object - route = api_instance.get_namespaced_custom_object( - group="route.openshift.io", - version="v1", - namespace=namespace, - plural="routes", - name=route_name - ) - - # Extract spec.host field - route_host = route['spec']['host'] - return route_host - - except Exception as e: - print(f"Error: {e}") - return None - -# Get the service account token or return None -def get_token(): - try: - with open("/var/run/secrets/kubernetes.io/serviceaccount/token", "r") as f: - return f.read().strip() - except Exception as e: - print(f"Error: {e}") - return None - -# Function that generates a Dict from an Input[Metrics] object -def metrics_to_dict(metrics_input: Input[Metrics]) -> dict: - # Inspecting the Input[Metrics] object - print(f"metrics_input: {metrics_input}") - print(f"metrics_input.metadata: {metrics_input.metadata}") - - # Get all key:values from metrics_input.metadata - metrics_dict = {} - - # If metrics_input or metrics_input.metadata is None - if metrics_input is None or metrics_input.metadata is None: - return metrics_dict - - # Loop through the metrics_input.metadata and add key:values to metrics_dict - for key, value in metrics_input.metadata.items(): - metrics_dict[key] = value - - # Print the metrics_dict - print(f"metrics_dict: {metrics_dict}") - - # Return the metrics_dict - return metrics_dict - \ No newline at end of file diff --git a/components/register_model/uv.lock b/components/register_model/uv.lock index 2776fab..2a35f0b 100644 --- a/components/register_model/uv.lock +++ b/components/register_model/uv.lock @@ -473,7 +473,7 @@ wheels = [ [[package]] name = "model-registry" -version = "0.2.13" +version = "0.2.21" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -484,9 +484,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/d4/adfd60b71709f54f2af56a355662032ab97fa218487290e7a3eed4e05a6d/model_registry-0.2.13.tar.gz", hash = "sha256:deebf9e4f0cba4efd20d3977b84913a0bbf6c482f79b356c3e6314ae82039a76", size = 60149 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/b7/0254b6d660b46b1e8f74e7b8f5b0d6c5ae4b083c4c294649f56bb60671ad/model_registry-0.2.21.tar.gz", hash = "sha256:07eb145fedf519c16cdd9151f49d53fa6b10b68dfd81a92e67f4c9e2b7f6c244", size = 72602 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/0a/4f0329dac1c5e0edf29d03fb995b163f8cc7a90ce98f1a75c9a6e2c6affd/model_registry-0.2.13-py3-none-any.whl", hash = "sha256:502cfe40712159d630e1d7b1d24ac995ec9999a4d3bb29a2c8d95c0fad9f5a2d", size = 139093 }, + { url = "https://files.pythonhosted.org/packages/c7/33/737f428a7d8410bef207746271c4a874a5697b78cb685ff16e689ee21c4d/model_registry-0.2.21-py3-none-any.whl", hash = "sha256:1546fb3b9f888a01b34307d330078241bae1244a123a83b008c85e9384e29205", size = 143552 }, ] [[package]] @@ -754,7 +754,7 @@ requires-dist = [ { name = "kfp", extras = ["kubernetes"], specifier = "==2.8.0" }, { name = "kubernetes", specifier = "==23.6.0" }, { name = "load-dotenv", specifier = "==0.1.0" }, - { name = "model-registry", specifier = "==0.2.13" }, + { name = "model-registry", specifier = "==0.2.21" }, ] [[package]] diff --git a/components/run-component.sh b/components/run-component.sh new file mode 100755 index 0000000..4262a7e --- /dev/null +++ b/components/run-component.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Source the .env file +. .env + +# If there is not exactly one argument and is not in the COMPONENTS array, print usage and exit +if [ "$#" -ne 1 ] || ! [[ " ${COMPONENTS[@]} " =~ " ${1} " ]]; then + echo "Usage: $0 ${COMPONENTS[@]}" + exit 1 +fi + +# Set the COMPONENT_NAME variable to the first argument +COMPONENT_NAME=$1 + +# Source the component-specific environment variables if the file exists +[ -f ${COMPONENT_NAME}/.env ] && . ${COMPONENT_NAME}/.env + +# Print info +echo "COMPONENT_NAME: ${COMPONENT_NAME}" +echo "BASE_IMAGE: ${BASE_IMAGE}" +echo "REGISTRY: ${REGISTRY}" +echo "TAG: ${TAG}" + +# Run the component image +podman run -it --rm localhost/${COMPONENT_NAME}:${TAG} bash +# podman run -it --rm --entrypoint bash localhost/${COMPONENT_NAME}:latest diff --git a/components/shared/__init__.py b/components/shared/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/components/shared/kubeflow.py b/components/shared/kubeflow.py new file mode 100644 index 0000000..3e8324f --- /dev/null +++ b/components/shared/kubeflow.py @@ -0,0 +1,163 @@ +import os +import time +import sys + +from typing import Optional + +from kubernetes import client as k8s_cli, config as k8s_conf + +import kfp +from kfp import client as kfp_cli, compiler +from kfp.dsl import base_component + +# Get token path from environment or default to kubernetes token location +TOKEN_PATH = os.environ.get("TOKEN_PATH", "/var/run/secrets/kubernetes.io/serviceaccount/token") + +# Get the service account token or return None +def get_token(): + try: + with open(TOKEN_PATH, "r") as f: + return f.read().strip() + except Exception as e: + print(f"Error: {e}") + return None + +# Get the route host for the specified route name in the specified namespace +def get_route_host(route_name: str): + # Load in-cluster Kubernetes configuration but if it fails, load local configuration + try: + k8s_conf.load_incluster_config() + except k8s_conf.config_exception.ConfigException: + k8s_conf.load_kube_config() + + # Get token path from environment or default to kubernetes token location + NAMESPACE_PATH = os.environ.get("NAMESPACE_PATH", "/var/run/secrets/kubernetes.io/serviceaccount/namespace") + + # Get the current namespace + with open(NAMESPACE_PATH, "r") as f: + namespace = f.read().strip() + + print(f"namespace: {namespace}") + + # Create Kubernetes API client + api_instance = k8s_cli.CustomObjectsApi() + + try: + # Retrieve the route object + route = api_instance.get_namespaced_custom_object( + group="route.openshift.io", + version="v1", + namespace=namespace, + plural="routes", + name=route_name + ) + + # Extract spec.host field + route_host = route['spec']['host'] + return route_host + + except Exception as e: + print(f"Error: {e}") + return None + +def get_pipeline_id_by_name(client: kfp_cli.Client, pipeline_name: str): + return client.get_pipeline_id(pipeline_name) + +def get_pipeline(client: kfp_cli.Client, pipeline_id: str): + return client.get_pipeline(pipeline_id) + +def get_latest_pipeline_version_id(client: kfp_cli.Client, pipeline_id: str) -> Optional[str]: + pipeline_versions = client.list_pipeline_versions( + pipeline_id=pipeline_id, + sort_by="created_at desc", + page_size=10 + ) + if pipeline_versions and len(pipeline_versions.pipeline_versions) >= 1: + # Order pipeline_versions by created_at in descending order and return the first one + pipeline_versions.pipeline_versions.sort(key=lambda x: x.created_at, reverse=True) + return pipeline_versions.pipeline_versions[0].pipeline_version_id + else: + return None + +# Function that create a kpf experiment and returns the id +def create_experiment(client: kfp_cli.Client, experiment_name: str) -> str: + experimment = client.create_experiment(name=experiment_name) + print(f">>>experimment: {experimment}") + return experimment.experiment_id + +# Function that creates a run of a pipeline id in a given experiment id with the latest version of the pipeline +def create_run(client: kfp_cli.Client, pipeline_id: str, experiment_id: str, run_name: str, params: dict) -> str: + pipeline_version_id = get_latest_pipeline_version_id(client, pipeline_id) + print(f">>>pipeline_version_id: {pipeline_version_id}") + if pipeline_version_id is None: + raise ValueError(f"No pipeline versions found for pipeline_id: {pipeline_id}") + run = client.run_pipeline( + experiment_id=experiment_id, + job_name=run_name, + pipeline_id=pipeline_id, + version_id=pipeline_version_id, + params=params + ) + print(f"run: {run}") + return run.run_id + +# Function that compiles and upserts a pipeline +def compile_and_upsert_pipeline( + pipeline_func: base_component.BaseComponent, + pipeline_package_path: str, + pipeline_name: str) -> str: + + # Compile the pipeline + compiler.Compiler().compile( + pipeline_func=pipeline_func, + package_path=pipeline_package_path, + ) + + # Take token and kfp_endpoint as optional command-line arguments + token = sys.argv[1] if len(sys.argv) > 1 else None + kfp_endpoint = sys.argv[2] if len(sys.argv) > 2 else None + + if not token: + print("Token endpoint not provided finding it automatically.") + token = get_token() + + if not kfp_endpoint: + print("KFP endpoint not provided finding it automatically.") + kfp_endpoint = get_route_host(route_name="ds-pipeline-dspa") + + # If both kfp_endpoint and token are provided, upload the pipeline + if kfp_endpoint and token: + client = kfp.Client(host=kfp_endpoint, existing_token=token) + + # If endpoint doesn't have a protocol (http or https), add https + if not kfp_endpoint.startswith("http"): + kfp_endpoint = f"https://{kfp_endpoint}" + + try: + # Get the pipeline by name + print(f"Pipeline name: {pipeline_name}") + pipeline_id = get_pipeline_id_by_name(client, pipeline_name) + if pipeline_id: + print(f"Pipeline {pipeline_id} already exists. Uploading a new version.") + # Upload a new version of the pipeline with a version name equal to the pipeline package path plus a timestamp + pipeline_version_name=f"{pipeline_name}-{int(time.time())}" + client.upload_pipeline_version( + pipeline_package_path=pipeline_package_path, + pipeline_id=pipeline_id, + pipeline_version_name=pipeline_version_name + ) + print(f"Pipeline version uploaded successfully to {kfp_endpoint}") + else: + print(f"Pipeline {pipeline_name} does not exist. Uploading a new pipeline.") + print(f"Pipeline package path: {pipeline_package_path}") + # Upload the compiled pipeline + client.upload_pipeline( + pipeline_package_path=pipeline_package_path, + pipeline_name=pipeline_name + ) + print(f"Pipeline uploaded successfully to {kfp_endpoint}") + except Exception as e: + print(f"Failed to upload the pipeline: {e}") + else: + print("KFP endpoint or token not provided. Skipping pipeline upload.") + diff --git a/components/shared/utils.py b/components/shared/utils.py new file mode 100644 index 0000000..988b339 --- /dev/null +++ b/components/shared/utils.py @@ -0,0 +1,51 @@ +from cProfile import label +from kubernetes import client as k8s_cli, config as k8s_conf + +# Function that gets the model registry endpoint using a route object +def get_model_registry_endpoint(model_registry_name: str, + namespace: str) -> str: + """ + Get the model registry endpoint from the route object in the specified namespace. + Args: + model_registry_name (str): Name of the model registry + namespace (str): Namespace where the model registry route is located + Returns: + str: The model registry endpoint URL if found, otherwise None + """ + print(f"Retrieving model registry endpoint for {model_registry_name} in namespace {namespace}") + # Load in-cluster Kubernetes configuration but if it fails, load local configuration + try: + k8s_conf.load_incluster_config() + except k8s_conf.config_exception.ConfigException: + k8s_conf.load_kube_config() + + # Create Kubernetes API client + api_instance = k8s_cli.CustomObjectsApi() + + # Selector to find the route by app label + label_selector = f"app.kubernetes.io/name={model_registry_name}" + print(f"Using label selector: {label_selector}") + + try: + # Retrieve the route object + routes = api_instance.list_namespaced_custom_object( + group="route.openshift.io", + version="v1", + namespace=namespace, + plural="routes", + label_selector=label_selector + ) + + # Extract spec.host fields + route_hosts = [route['spec']['host'] for route in routes['items']] + print(f"Found route hosts: {route_hosts}") + + # Return the route host only if it contains "-http" else return None + for route_host in route_hosts: + if "-rest" in route_host: + return f'https://{route_host}' + return None + + except Exception as e: + print(f"Error: {e}") + return None \ No newline at end of file diff --git a/deploy-model.sh b/deploy-model.sh index bb0a041..cfb2904 100755 --- a/deploy-model.sh +++ b/deploy-model.sh @@ -131,7 +131,7 @@ spec: - name: model.runtime.templateName value: "${MODEL_FAMILY}-${MODEL_SIZE}-serving-template" - name: model.accelerator.productName - value: "NVIDIA-A10G" + value: "NVIDIA-A10G-SHARED" - name: model.accelerator.min value: '1' - name: model.accelerator.max diff --git a/gitops/model/README.md b/gitops/model/README.md index d3304ae..09ee82a 100644 --- a/gitops/model/README.md +++ b/gitops/model/README.md @@ -424,7 +424,7 @@ oc create secret generic hf-creds \ DATA_SCIENCE_PROJECT_NAMESPACE=embeddings-gpu RUNTIME_MODEL_ID="multilingual-e5-large-gpu" INFERENCE_URL=$(oc get inferenceservice/${RUNTIME_MODEL_ID} -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -o jsonpath='{.status.url}') -INFERENCE_URL=$(oc get route/${RUNTIME_MODEL_ID} -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -o jsonpath='{.spec.host}') +INFERENCE_URL=$(oc get route/${RUNTIME_MODEL_ID}-predictor -n ${DATA_SCIENCE_PROJECT_NAMESPACE} -o jsonpath='{.spec.host}') echo ${INFERENCE_URL} curl -s -X 'POST' \ From e5f56763a4dd8df5757f827f24ed77c6de04afdb Mon Sep 17 00:00:00 2001 From: cvicens Date: Mon, 25 Aug 2025 18:20:18 +0200 Subject: [PATCH 05/18] not needed --- .../src/__pycache__/train_yolo.cpython-311.pyc | Bin 13490 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 components/register_model/src/__pycache__/train_yolo.cpython-311.pyc diff --git a/components/register_model/src/__pycache__/train_yolo.cpython-311.pyc b/components/register_model/src/__pycache__/train_yolo.cpython-311.pyc deleted file mode 100644 index 4dad1ffcbe50276af9437bdf7e0749a4ee3e181d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13490 zcmdTqTWlLgl0$JQ4yoZoq+XOniF%8YNa`(HmhH&0EGyQ-*251aw_I8?l4$d_L&}c1 zqeL47IKv3wT#!R_*#yfA7Ks;|kNh0qI|R4|?mq5gKYEM-Obie}z-=zsKN_0_7WumB z=0hA>a^%J0fTMc4tE;Q3yQ{maXR7qM$z-J9H?@CrbJ0yv|BWm8pEn2mX{C&!KBPE` z(}busT$Y72;j*Z!unvth&RpiB| z*gRBRa(a&W4Ep;mJlWrx=@?uF&d8g7NqtgQ!fWQuzofW|Ps-LT9J^-aOly^#dCkUI z*6f^ht%|E$t1hE>!>yWpZ@iJWa5mnGWpQ@Cl9W}vjg-~Aos>0v6)9`^YFuuXe^K|D z7RC%u_QyH+TCSe2;~L;;gvSZ>Cf>m{!{dUd1)f%T+Tdx2whnkY;pu{>8y+`2J@E9x z(+4ADc*kcN=mDNw4<3T8Ex~&Ea$fJq6Hyy|obMg_GpPTzfLp8Q8@T@4M8CoW-p7cOvD;n_(c~5!<`v->y;HMZCCg-P@FHcTQD|(LK z2yBNE3bQmlGrPR9bR#)H#CZgMGZ;?@_q@>UPr$kptz!1`^hE`K8G4@TmNKq#abL7jZa9|?qc#YnjP z@nDiy%K2DyeG69NW+1V?mBksNF;F_R3W_Pj2ZTs4vgsFK&I%KbhWSWhJFKvG`QYYO z!q4&RfqP2TdNi^T*lu|+%CVSI=ClK1^{n6}(tvt|P9#sRggawV~>i#TSe7#_F;1F2g!RF&n zzpEm~R>M&tYNv+7rDms=lw~`0q}1*>pezf~VckxBxO}GpA1R>I?=(WG4KZQEj#ER4 zHMfXy2dPx5V0LjW|Kn)2`PgYX29K_Ur}-E>WANxpcv=z%c8%f~u?d@AHI0T+ z(HKP6kJ1>$mLH|55VKc{$^e)2#flX_D#s*Rew4;6lB?&1^RkHKT6!UkRU}u|3u!7v zxE!C?p=cKBVSP;bU6L~Aq2f|Bt7XUSiNe)DQJf9S=Iozn)l_e5RFbX567#SKIuI@D z3w5Ve#dr9KTGf4(jHpU%g%MT%l_RpLFR`7rV~nS*WIWa~d?qUk^DJp6C-y+=hwG+Q ztSlKxyK2wZi0v@T+R|B;$UabYs4$*PTo~KNKjeY*7 z?o;q^Ejt~md9|u!R6j2P_I*j;hv^~W133lTf2%ex=UAhvc)tIU;)^#2hyS{L%H9bP@bc>CthCD@a$@Sn{mFva# zCgk{L)Tylv*pZ`n`@m+aKHOeF>k+NTruCLuycfvzi5YyY&d!1^i3NKBbb~c7*H#{-tD3sARVvA-jNoDcPr0vOA8DUBDkI`_SF6 z(-X0%cJ-OkeXMFdE4CeGpSf4Ec6+B+MLj9@9!3o}`;Wcxv|&zi|ER3XPM=EtS+Va> z`JJiGyoQQPvG0X*J9mV%;?W-d4pkyIZd1KOO&ul|-iaGiUB#oz!|EFo&fvj~d;V{7 z<9bv&JnF_h>TdBof49IGJ5$~H@fVlsx$JmV*35f|HTwl<<#1~@EqV{LX3tryqxdhV z_zRZl*!(jp{(|*6HvdHxf5E~Wn}1ftU$7#_=6_YiU$7L<@gHUJkE{Qq_>Zgqqxg@j z|D*VitN)|;kE{Qq_>ZaoAG5~be22f%Rf|-#Q3F(*zFYQ&_6BuVqoHn48u){A2@d|} zf83=n=G3-u$0z#Y>YHF*O##x1E#cvB(^wY_^}UuaX~TVh|aA} zU7B7|s%PgXXQqK_a%FOPdIhszn!b^&Tpk*C@ewW-4T9%)TL`(5R*bs2y?#6A^>rod zF-GnB^~Z<&xA}Xnq^a1A49q1CXIHYSgc1A4UCBl@R^=dmo(H>MqJ5;=V=O!ihX|W!rbCD|H{(j z)TP;l8UO0itWuLhPG7$~y)-*Ny|CiPQ5L1Tlz3(F()5B-o{eLyDBAVdwnDFObAhCJ zH4Yob#qoE7>-@M&(S~F3WThH8e|b5n^~Ms4#*@^0NYurXv`uXb0>lYi5Fv2kMH+Xx zH3I(LRoHwG0MGLWjqd<(T8N1V*yk;b zL$(PI`6=3)(KnJf>OuPSg#)pqxwtmcuda`cBr6WuW5pGrs1jLEwk||nAlwy5K+Nst zc7n&tpV;DExd28>OADN;z@3AsCZeunIhnO5Sw+;qb2%+!RiCuX<7kpA9=HQ7n7lTN zxEsiB<7`79;Y#W}5J-WAgq%#ukON>oc@U;jPO!0DDP+sYx{&<~lS!{l)RzbGqu z2Zq@6hkPw z39&OF5QeGXU8d-_0&%=26eDiRhOdNkScDdKpQ3|oq@NUHBT88~29KbW;YGo#i)Y9Y z$y!)D2qTi^z?(dF50(uAs*3Ke5QLba7DBA^3Y1pHEwJuUdCkz*oYx9!0(5wPb} zz;4X!DZvgfa?S0=};V7tZjzzJOoY1^m`6;8$ni0?uY|b`fW@I8!fI zcAePb+eN9s5#eYq1X)pZ%P7_A8zFbWJcrH&8%<smPe{%{DdpgwnA6}C7+so2PB@*IRm3jyA0H7=HmnzFD`2l8!D3&JkL6V8in zP&49FL^t?bFuXIsBKVd(dI2z_L#_BX!!hSAQ`6 z;hFc(pw=PDJ}ldZL5!{HgPsq)?|V_ph-4d;ZKJ!F3b<6WWE+re1AuC5`uNpfEqt_q zde2FXQ*z@Jq8;DR24w8p3qb}+qCGP0LA2*4wSIi}SK>z^ z>YGGUSEc4_a`QDrHA1t?Wp*karR} zws5+#kp(1kP&Nk<6C^Uvq3&0Z@f;+Ho|0+UK2tCX_sH(KcV0!7c8Tst_l{>PT@u|5 zZN0;f+`sAlqBo1|l;|!%>P&yX`1ay^*Y^^r3Ny)c2ckQm!EE2Xkk+&BB%kV=p6Ht- zy-U`+GL#OcUs-#<{A zz?drUpMURFRN0nI65B4b?Yq;^;%GtD7a^s_v*o|6KW_hb_rJOSwfC!DY4n0TdLfJ7 zT_FAW_TEHBA0&zHm+5{)_k)Zhw^+Kl<slPn-H0htLPCQw9-+!GRWT4qio=5zs# z96mHKCo%IfGmn`00)DUQQ1ZRH)TqSt$V?AndJc#iQ%Q*#l$k-q3?5*?VIVOcneiaT z^9|lmt0^O7IE^pm0Q0KET$P!th`E}!)qdFfes8+kldg59Yg{^X?~UzEOBJnhMe8%lXgHB(Tc5I?C#>gD z1YNl6sr^my~D+h0W=N0G2Cv3F$l4r1>VNRjspT76w!{i(dVfmVgz>Ho7r ze&q^+^v2I6R+L#0vEpAz{V4ojcYpu$-@l0#gO9I$_1afIdHfR;6(lw;vvI`63sV0^ zbo&jhAD{a8?ESg>bKkI)$TljmV=_C2*s(vCQwB3K_otkYL6VpOnHfOLK-xK)iXi7G zPE0*91Se6)7&4!PBr)SMGmek`p?-<*++ke&R#(iSF=fSU6Wnc5aT3#Cs4~M zGM|7XF(+l_Bw|jc8Ph}K10%9`ON?7)+=y`#(lO*3L1yS>Okz&R%n8JtfKzIe@(^o5+F|$LJvsy@&O8K3VuodA7%{_Xll`g5`NZT*iOA%XOvADX#$h*1 zkZixD^K-|ij(=|Wbpv9XK&#eTRO@~;B3TAx%fK_rY??@0Yo1zLo>*H_Zsa*Dd!}U1 zjAXqiTQ4H(#e>FP;C%VU z&ZpLaC)R;4-RSh9e0o_veND1nm#x>4^?KTxZ|sF-m(Q-sXJ3=7ugligk@fXsHg=-NvS7qx}WW9R8`Ld0`{Ef95)r?ElQ?m6GvYyIx<(G!6&ojJI-xrqaVBt!j zzx?GdC75irkLv3CJoIVkac3$dbxz8ilZa_cTi}k<7*2hS&(ukY9hcd0#E!#mYwLiw zoxV@|9_^sXWprjOo21s)1 z&ODewRh<&sC9_?K?aFAOg*21w87BN5X9u{$Afle5KxV7TjC9aR43Y|Uni?%Qfi^lb~h*pkSmPeAIAUY?8h#+dr6%af2)GW z*OdR{@^5T|3xLi2i!u2)bhiljb6Y7BctMK+?d^@2Kx0S`kQe@|ThKvGD94!|XAEvM zo&#U6pLl+SIgFjhnE_|`A6pf6WpZf-oWX=bsRi%x(&XHYmD#Cf|K-`s{;ShV%h;7% zJGVG_-hX~^WqRSNs-bdWb^h`V70Q-#RjT;0=V)nlVFg^8D&i{KuskAej<&A^U-ufUo=Q5PwGa2&x)*;{O4@c-TG~O`0<7lD{-%Me4Lq)gg7-r+nz> zl&0)Ro%SoP>>9xwnJn+V`f%aF!rrMz28kV%*}+}IzMAGf|+v*WjnYK3|%9hUJtDT6d+SizO?e93#7Du|$ znRc8*?pF}xkj{tE%59vV52qcYsBIWQ4(Y@-G_{KJ6W7%Ao9GIU&Tm4>=*k>HO-5f{ zR`!g7?0cML%vZIVv9#5m(PCg9038PKOsyF`0U4^YDq|p^kphAW0x(L`!)wl1}r=}%GkL>8lxCyd{s%w2OnQHro zw?23)(@Ri&l(Q{0_VHrIL#ot4{>-A*PbOAQ(d_-?6RiVj9sACXr%ulkr{@v> Date: Mon, 25 Aug 2025 18:20:48 +0200 Subject: [PATCH 06/18] fixes to the modelregistry template to avoid issues in 2.23 --- gitops/model-registry/run.sh | 2 +- .../templates/model-registry.yaml | 72 +++++++++---------- gitops/model-registry/values.yaml | 37 +++++----- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/gitops/model-registry/run.sh b/gitops/model-registry/run.sh index f0471f8..d389746 100755 --- a/gitops/model-registry/run.sh +++ b/gitops/model-registry/run.sh @@ -1,5 +1,5 @@ #!/bin/sh -ARGOCD_APP_NAME=model-registry +ARGOCD_APP_NAME=model-registry-dev # Load environment variables DATA_SCIENCE_PROJECT_NAMESPACE="model-registry" diff --git a/gitops/model-registry/templates/model-registry.yaml b/gitops/model-registry/templates/model-registry.yaml index d45822e..9b8b005 100644 --- a/gitops/model-registry/templates/model-registry.yaml +++ b/gitops/model-registry/templates/model-registry.yaml @@ -9,10 +9,15 @@ metadata: openshift.io/description: "" openshift.io/display-name: {{ include "model-registry.fullname" . }} spec: + {{- with .Values.registry.grpc }} grpc: - image: {{ .Values.registry.grpc.image | default "quay.io/opendatahub/model-registry:v0.2.12" }} - port: {{ .Values.registry.grpc.port | default 9090 }} - {{- with .Values.registry.grpc.resources }} + {{- if .image }} + image: {{ .image }} + {{- end }} + {{- if .port }} + port: {{ .port | default 9090 }} + {{- end }} + {{- with .resources }} resources: limits: cpu: {{ .limits.cpu | default "100m" }} @@ -21,41 +26,17 @@ spec: cpu: {{ .requests.cpu | default "100m" }} memory: {{ .requests.memory | default "256Mi" }} {{- end }} + {{- end }} - istio: - audiences: - - https://kubernetes.default.svc - authConfigLabels: - security.opendatahub.io/authorization-group: default - authProvider: redhat-ods-applications-auth-provider - gateway: - grpc: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - istioIngress: ingressgateway - rest: - gatewayRoute: enabled - port: 443 - tls: - credentialName: default-modelregistry-cert - mode: SIMPLE - tlsMode: ISTIO_MUTUAL - mysql: - database: metadb - host: {{ include "model-registry.fullname" . }}-db.rhoai-model-registries.svc.cluster.local - passwordSecret: - key: database-password - name: {{ include "model-registry.fullname" . }}-db - port: {{ .Values.registryDb.databasePort | default 3306 }} - skipDBCreation: false - username: root + {{- with .Values.registry.rest }} rest: - image: {{ .Values.registry.rest.image | default "quay.io/opendatahub/model-registry:v0.2.10" }} - port: 8080 - {{- with .Values.registry.rest.resources }} + {{- if .image }} + image: {{ .image }} + {{- end }} + {{- if .port }} + port: {{ .port | default 8080 }} + {{- end }} + {{- with .resources }} resources: limits: cpu: {{ .limits.cpu | default "100m" }} @@ -64,4 +45,21 @@ spec: cpu: {{ .requests.cpu | default "100m" }} memory: {{ .requests.memory | default "256Mi" }} {{- end }} - serviceRoute: disabled \ No newline at end of file + serviceRoute: {{ .serviceRoute }} + {{- end }} + + oauthProxy: + port: 8443 + routePort: 443 + serviceRoute: enabled + + mysql: + database: metadb + host: {{ include "model-registry.fullname" . }}-db.rhoai-model-registries.svc.cluster.local + passwordSecret: + key: database-password + name: {{ include "model-registry.fullname" . }}-db + port: {{ .Values.registryDb.databasePort | default 3306 }} + skipDBCreation: false + username: root + \ No newline at end of file diff --git a/gitops/model-registry/values.yaml b/gitops/model-registry/values.yaml index b1d505a..c30d590 100644 --- a/gitops/model-registry/values.yaml +++ b/gitops/model-registry/values.yaml @@ -3,25 +3,26 @@ kubernetesClusterDomain: cluster.local registry: namespace: rhoai-model-registries rest: - image: quay.io/opendatahub/model-registry:v0.2.10 - # port: 8080 - # resources: - # limits: - # cpu: 100m - # memory: 256Mi - # requests: - # cpu: 100m - # memory: 256Mi + # image: quay.io/opendatahub/model-registry:v0.2.10 + port: 8080 + serviceRoute: disabled + # resources: + # limits: + # cpu: 100m + # memory: 256Mi + # requests: + # cpu: 100m + # memory: 256Mi grpc: - image: registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8:v2.17.0 - # port: 9090 - # resources: - # limits: - # cpu: 100m - # memory: 256Mi - # requests: - # cpu: 100m - # memory: 256Mi + # image: registry.redhat.io/rhoai/odh-mlmd-grpc-server-rhel8:v2.17.0 + port: 9090 + # resources: + # limits: + # cpu: 100m + # memory: 256Mi + # requests: + # cpu: 100m + # memory: 256Mi pvc: metadataMysql: From daefd6bad61b8c2e171c280fe12007db1d99c7d4 Mon Sep 17 00:00:00 2001 From: cvicens Date: Mon, 25 Aug 2025 18:56:42 +0200 Subject: [PATCH 07/18] fixes to the modelregistry template to avoid issues in 2.23 --- gitops/model-registry/templates/model-registry.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/gitops/model-registry/templates/model-registry.yaml b/gitops/model-registry/templates/model-registry.yaml index 9b8b005..25e6883 100644 --- a/gitops/model-registry/templates/model-registry.yaml +++ b/gitops/model-registry/templates/model-registry.yaml @@ -60,6 +60,5 @@ spec: key: database-password name: {{ include "model-registry.fullname" . }}-db port: {{ .Values.registryDb.databasePort | default 3306 }} - skipDBCreation: false username: root \ No newline at end of file From 69547f0d959acc67df79f4d4d65155af72f37028 Mon Sep 17 00:00:00 2001 From: cvicens Date: Thu, 19 Feb 2026 10:10:05 +0100 Subject: [PATCH 08/18] oauthProxy not needed for now --- gitops/model-registry/templates/model-registry.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gitops/model-registry/templates/model-registry.yaml b/gitops/model-registry/templates/model-registry.yaml index 25e6883..971be8d 100644 --- a/gitops/model-registry/templates/model-registry.yaml +++ b/gitops/model-registry/templates/model-registry.yaml @@ -48,11 +48,6 @@ spec: serviceRoute: {{ .serviceRoute }} {{- end }} - oauthProxy: - port: 8443 - routePort: 443 - serviceRoute: enabled - mysql: database: metadb host: {{ include "model-registry.fullname" . }}-db.rhoai-model-registries.svc.cluster.local From 40272ca726f08028d25a2788f51293c189f9301f Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 17:49:59 +0100 Subject: [PATCH 09/18] Fix build... --- components/build-component.sh | 2 +- components/pyproject.toml | 15 + components/register_model/.gitignore | 1 + components/register_model/pyproject.toml | 5 +- .../component_metadata/register_model.yaml | 4 +- components/uv.lock | 1364 +++++++++++++++++ 6 files changed, 1385 insertions(+), 6 deletions(-) create mode 100644 components/pyproject.toml create mode 100644 components/register_model/.gitignore create mode 100644 components/uv.lock diff --git a/components/build-component.sh b/components/build-component.sh index 751c35f..3185049 100755 --- a/components/build-component.sh +++ b/components/build-component.sh @@ -27,7 +27,7 @@ export TAG # Build the component using the kfp CLI export PYTHONPATH=${PYTHONPATH}:$(pwd)/${COMPONENT_NAME}/src:$(pwd)/shared -kfp component build ${COMPONENT_NAME}/src/ --component-filepattern ${COMPONENT_NAME}.py --no-push-image --no-build-image +uv run kfp component build ${COMPONENT_NAME}/src/ --component-filepattern ${COMPONENT_NAME}.py --no-push-image --no-build-image # Build the image using the BASE_IMAGE build arg podman build -t ${COMPONENT_NAME}:${TAG} -f ./Containerfile . \ diff --git a/components/pyproject.toml b/components/pyproject.toml new file mode 100644 index 0000000..64a8359 --- /dev/null +++ b/components/pyproject.toml @@ -0,0 +1,15 @@ +[project] +name = "components" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "kfp==2.13.0", + "kfp[kubernetes]==2.13.0", + "boto3==1.35.54", + "botocore==1.35.54", + "kubernetes==23.6.0", + "load-dotenv==0.1.0", + "model-registry==0.2.21", +] diff --git a/components/register_model/.gitignore b/components/register_model/.gitignore new file mode 100644 index 0000000..bb6b88b --- /dev/null +++ b/components/register_model/.gitignore @@ -0,0 +1 @@ +pipeline.yaml \ No newline at end of file diff --git a/components/register_model/pyproject.toml b/components/register_model/pyproject.toml index c4f4724..f51f918 100644 --- a/components/register_model/pyproject.toml +++ b/components/register_model/pyproject.toml @@ -5,9 +5,8 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = [ - "boto3==1.35.54", - "botocore==1.35.54", - "kfp[kubernetes]==2.8.0", + "kfp==2.13.0", + "kfp[kubernetes]==2.13.0", "kubernetes==23.6.0", "load-dotenv==0.1.0", "model-registry==0.2.21", diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index d5a9cd2..66f9779 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -68,7 +68,7 @@ deploymentSpec: - python3 - -m - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:v1.0.2 + image: quay.io/atarazana/register_model:v1.0.3 pipelineInfo: name: register-model root: @@ -146,4 +146,4 @@ root: output_model_version_id: parameterType: STRING schemaVersion: 2.1.0 -sdkVersion: kfp-2.8.0 +sdkVersion: kfp-2.13.0 diff --git a/components/uv.lock b/components/uv.lock new file mode 100644 index 0000000..94d6c8f --- /dev/null +++ b/components/uv.lock @@ -0,0 +1,1364 @@ +version = 1 +requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version < '3.13'", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, +] + +[[package]] +name = "aiohttp" +version = "3.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732 }, + { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293 }, + { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533 }, + { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839 }, + { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932 }, + { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906 }, + { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020 }, + { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181 }, + { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794 }, + { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900 }, + { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239 }, + { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527 }, + { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489 }, + { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852 }, + { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379 }, + { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253 }, + { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407 }, + { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190 }, + { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783 }, + { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704 }, + { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652 }, + { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014 }, + { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777 }, + { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276 }, + { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131 }, + { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863 }, + { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793 }, + { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676 }, + { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217 }, + { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303 }, + { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673 }, + { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120 }, + { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383 }, + { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899 }, + { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238 }, + { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292 }, + { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021 }, + { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263 }, + { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107 }, + { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196 }, + { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591 }, + { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277 }, + { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575 }, + { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455 }, + { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417 }, + { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968 }, + { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690 }, + { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390 }, + { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188 }, + { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126 }, + { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128 }, + { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512 }, + { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444 }, + { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798 }, + { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835 }, + { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486 }, + { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951 }, + { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001 }, + { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246 }, + { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131 }, + { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196 }, + { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841 }, + { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193 }, + { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979 }, + { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193 }, + { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801 }, + { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523 }, + { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694 }, +] + +[[package]] +name = "aiohttp-retry" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981 }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, +] + +[[package]] +name = "boto3" +version = "1.35.54" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/e9/52e1db9abfc9ebd1ce8d7a0600f74b226c0b243e78def2b5d59ff8efe594/boto3-1.35.54.tar.gz", hash = "sha256:7d9c359bbbc858a60b51c86328db813353c8bd1940212cdbd0a7da835291c2e1", size = 110991 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/83/81c3d2199f2196493b1f67852e6361a082ca05dc5d976432b86808b7db82/boto3-1.35.54-py3-none-any.whl", hash = "sha256:2d5e160b614db55fbee7981001c54476cb827c441cef65b2fcb2c52a62019909", size = 139158 }, +] + +[[package]] +name = "botocore" +version = "1.35.54" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/56/5eacd3dcecdbc36cb5695676c165430282f83cb86ffa75a1a65c34c084c5/botocore-1.35.54.tar.gz", hash = "sha256:131bb59ce59c8a939b31e8e647242d70cf11d32d4529fa4dca01feea1e891a76", size = 12920483 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/cd/e79c87014d0ed371335273cbf8a2bc1fdd6dd2071ba6cb9efedb6e311504/botocore-1.35.54-py3-none-any.whl", hash = "sha256:9cca1811094b6cdc144c2c063a3ec2db6d7c88194b04d4277cd34fc8e3473aff", size = 12708560 }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230 }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043 }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446 }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101 }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948 }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422 }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499 }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928 }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302 }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320 }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487 }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049 }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793 }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300 }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244 }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828 }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926 }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773 }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013 }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593 }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354 }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480 }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584 }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443 }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425 }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162 }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558 }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497 }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240 }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471 }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864 }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647 }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110 }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839 }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667 }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535 }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816 }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694 }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131 }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390 }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091 }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936 }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180 }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346 }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874 }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076 }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601 }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376 }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825 }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583 }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366 }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300 }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465 }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404 }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092 }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408 }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746 }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889 }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641 }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779 }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035 }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542 }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524 }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395 }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680 }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045 }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687 }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014 }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044 }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940 }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104 }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "components" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "boto3" }, + { name = "botocore" }, + { name = "kfp", extra = ["kubernetes"] }, + { name = "kubernetes" }, + { name = "load-dotenv" }, + { name = "model-registry" }, +] + +[package.metadata] +requires-dist = [ + { name = "boto3", specifier = "==1.35.54" }, + { name = "botocore", specifier = "==1.35.54" }, + { name = "kfp", specifier = "==2.13.0" }, + { name = "kfp", extras = ["kubernetes"], specifier = "==2.13.0" }, + { name = "kubernetes", specifier = "==23.6.0" }, + { name = "load-dotenv", specifier = "==0.1.0" }, + { name = "model-registry", specifier = "==0.2.21" }, +] + +[[package]] +name = "cryptography" +version = "46.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289 }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637 }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742 }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528 }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993 }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855 }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635 }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038 }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181 }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482 }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497 }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819 }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230 }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909 }, + { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287 }, + { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728 }, + { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287 }, + { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539 }, + { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199 }, + { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131 }, + { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072 }, + { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170 }, + { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741 }, + { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728 }, + { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001 }, + { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637 }, + { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487 }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514 }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349 }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667 }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980 }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143 }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674 }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801 }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755 }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539 }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794 }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160 }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123 }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220 }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050 }, +] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896 }, +] + +[[package]] +name = "eval-type-backport" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830 }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782 }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594 }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448 }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411 }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014 }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909 }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049 }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485 }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619 }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320 }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820 }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518 }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096 }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985 }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591 }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102 }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717 }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651 }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417 }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391 }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048 }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549 }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833 }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363 }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314 }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365 }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763 }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110 }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717 }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628 }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882 }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676 }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235 }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742 }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725 }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506 }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161 }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676 }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638 }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067 }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101 }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901 }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395 }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659 }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492 }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034 }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749 }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127 }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698 }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749 }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298 }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015 }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038 }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130 }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845 }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131 }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542 }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308 }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210 }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972 }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536 }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330 }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627 }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238 }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738 }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739 }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186 }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196 }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830 }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289 }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318 }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814 }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762 }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470 }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042 }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148 }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676 }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451 }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, +] + +[[package]] +name = "google-api-core" +version = "2.30.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/27/09c33d67f7e0dcf06d7ac17d196594e66989299374bfb0d4331d1038e76b/google_api_core-2.30.0-py3-none-any.whl", hash = "sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5", size = 173288 }, +] + +[[package]] +name = "google-auth" +version = "2.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/41/242044323fbd746615884b1c16639749e73665b718209946ebad7ba8a813/google_auth-2.48.0.tar.gz", hash = "sha256:4f7e706b0cd3208a3d940a19a822c37a476ddba5450156c3e6624a71f7c841ce", size = 326522 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/1d/d6466de3a5249d35e832a52834115ca9d1d0de6abc22065f049707516d47/google_auth-2.48.0-py3-none-any.whl", hash = "sha256:2e2a537873d449434252a9632c28bfc268b0adb1e53f9fb62afc5333a975903f", size = 236499 }, +] + +[[package]] +name = "google-cloud-core" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469 }, +] + +[[package]] +name = "google-cloud-storage" +version = "3.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/b1/4f0798e88285b50dfc60ed3a7de071def538b358db2da468c2e0deecbb40/google_cloud_storage-3.9.0.tar.gz", hash = "sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc", size = 17298544 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/0b/816a6ae3c9fd096937d2e5f9670558908811d57d59ddf69dd4b83b326fd1/google_cloud_storage-3.9.0-py3-none-any.whl", hash = "sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066", size = 321324 }, +] + +[[package]] +name = "google-crc32c" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300 }, + { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867 }, + { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364 }, + { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740 }, + { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437 }, + { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297 }, + { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867 }, + { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344 }, + { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694 }, + { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435 }, + { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301 }, + { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868 }, + { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381 }, + { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734 }, + { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878 }, +] + +[[package]] +name = "google-resumable-media" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340 }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.72.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515 }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, +] + +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419 }, +] + +[[package]] +name = "kfp" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "docstring-parser" }, + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-storage" }, + { name = "kfp-pipeline-spec" }, + { name = "kfp-server-api" }, + { name = "kubernetes" }, + { name = "protobuf" }, + { name = "pyyaml" }, + { name = "requests-toolbelt" }, + { name = "tabulate" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/8e/cc5418e615c6923914911b43971c04509bf06153b6113e9e64ecdcc9e8c3/kfp-2.13.0.tar.gz", hash = "sha256:bd3e820452157472614217849f7a1cfd9c5d0d3cc7473ace80b6494ca06e8886", size = 269066 } + +[package.optional-dependencies] +kubernetes = [ + { name = "kfp-kubernetes" }, +] + +[[package]] +name = "kfp-kubernetes" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "kfp" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/b8/d41ed305110e4348b6c0828c9e8065aafe215db9ac4165f6b02da02a276e/kfp-kubernetes-1.5.0.tar.gz", hash = "sha256:84c2080f25934d21484f7a48eadbfd1f01f213fde0feb77f65346dbc544c855f", size = 16441 } + +[[package]] +name = "kfp-pipeline-spec" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/c4/5a42b32bddae9884b0ab23135f39e49ddb510b56ba9990757c6f873b87ae/kfp_pipeline_spec-0.6.0-py3-none-any.whl", hash = "sha256:9e319b62eaa54c6790a96f796d34f071458c9cae9585c662629eb090688555a7", size = 9081 }, +] + +[[package]] +name = "kfp-server-api" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "python-dateutil" }, + { name = "six" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/5c/10c7cd96cee27da45a1b90d2a95f7ec76876673fdcb0c391110ec7e75089/kfp_server_api-2.4.0.tar.gz", hash = "sha256:9d71ce49fc6757af14b052cc47e4cb531cb4e4584c2ea76ec02b9197ee9a674f", size = 83953 } + +[[package]] +name = "kubernetes" +version = "23.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "google-auth" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "setuptools" }, + { name = "six" }, + { name = "urllib3" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/a5/e50dbde38d54aa38a191204d6e446c7b41c1ab67354a2f652e971a4b5932/kubernetes-23.6.0.tar.gz", hash = "sha256:cadb1cd7c44eae5b39b50316313343c0f2aff94529f067ec2ba44d38411158e3", size = 753201 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/0e/307280c6d531f68d36411f0affdd25d510ad4e640f4f19da1b8b23331578/kubernetes-23.6.0-py2.py3-none-any.whl", hash = "sha256:dd58e286a53071bc8e32041f07f3c2236b3ed8ca5b9f57794a5077358f7ccb06", size = 1524068 }, +] + +[[package]] +name = "load-dotenv" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/95/055d123dde74bd54b99b27a3c2d8c6e218f544e0bd437480f61ccf85a07f/load-dotenv-0.1.0.tar.gz", hash = "sha256:bbe5f40072d4a61eadca66de6c222df5a2d935d6d41b703be1ff75396f635145", size = 6404 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2e/268a528dfa1f76999435634b0453fdd917ea878a818a6d5981632f7acffb/load_dotenv-0.1.0-py3-none-any.whl", hash = "sha256:614803f720153fb8a5f97124a72aaa3930a67aa5547cbe8603d01ea7f9ac1adf", size = 7175 }, +] + +[[package]] +name = "model-registry" +version = "0.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "eval-type-backport" }, + { name = "nest-asyncio" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/b7/0254b6d660b46b1e8f74e7b8f5b0d6c5ae4b083c4c294649f56bb60671ad/model_registry-0.2.21.tar.gz", hash = "sha256:07eb145fedf519c16cdd9151f49d53fa6b10b68dfd81a92e67f4c9e2b7f6c244", size = 72602 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/33/737f428a7d8410bef207746271c4a874a5697b78cb685ff16e689ee21c4d/model_registry-0.2.21-py3-none-any.whl", hash = "sha256:1546fb3b9f888a01b34307d330078241bae1244a123a83b008c85e9384e29205", size = 143552 }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893 }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456 }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872 }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018 }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883 }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413 }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404 }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456 }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322 }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955 }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254 }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059 }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588 }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642 }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377 }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887 }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053 }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307 }, + { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174 }, + { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116 }, + { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524 }, + { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368 }, + { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952 }, + { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317 }, + { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132 }, + { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140 }, + { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277 }, + { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291 }, + { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156 }, + { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742 }, + { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221 }, + { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664 }, + { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490 }, + { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695 }, + { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884 }, + { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122 }, + { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175 }, + { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460 }, + { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930 }, + { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582 }, + { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031 }, + { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596 }, + { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492 }, + { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899 }, + { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970 }, + { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060 }, + { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888 }, + { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554 }, + { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341 }, + { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391 }, + { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422 }, + { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770 }, + { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109 }, + { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573 }, + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190 }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486 }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219 }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132 }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420 }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510 }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094 }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786 }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483 }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403 }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315 }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528 }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784 }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980 }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602 }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930 }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074 }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471 }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401 }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143 }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507 }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358 }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884 }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878 }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542 }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403 }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889 }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982 }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415 }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337 }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788 }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842 }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237 }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008 }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542 }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719 }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319 }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065 }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061 }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037 }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324 }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505 }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242 }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474 }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575 }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736 }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019 }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376 }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988 }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615 }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066 }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655 }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789 }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750 }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780 }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308 }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182 }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215 }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112 }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442 }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398 }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920 }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748 }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877 }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437 }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586 }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790 }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158 }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451 }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374 }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396 }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950 }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856 }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420 }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254 }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205 }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873 }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739 }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514 }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781 }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396 }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897 }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789 }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152 }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869 }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596 }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981 }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490 }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371 }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424 }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566 }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130 }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625 }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209 }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797 }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140 }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257 }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097 }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455 }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372 }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411 }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712 }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557 }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015 }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880 }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938 }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641 }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510 }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161 }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393 }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546 }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259 }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, +] + +[[package]] +name = "proto-plus" +version = "1.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480 }, +] + +[[package]] +name = "protobuf" +version = "4.25.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745 }, + { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736 }, + { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537 }, + { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005 }, + { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924 }, + { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757 }, +] + +[[package]] +name = "pyasn1" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", size = 146586 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", size = 83371 }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172 }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990 }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003 }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200 }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578 }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504 }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816 }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366 }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698 }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603 }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591 }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068 }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908 }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145 }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179 }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403 }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206 }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307 }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258 }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917 }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186 }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164 }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146 }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788 }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133 }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852 }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679 }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766 }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005 }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622 }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725 }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040 }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691 }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897 }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302 }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877 }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680 }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960 }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102 }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039 }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126 }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489 }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288 }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255 }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760 }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092 }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385 }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832 }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585 }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078 }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914 }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560 }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244 }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955 }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906 }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607 }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179 }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481 }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, +] + +[[package]] +name = "s3transfer" +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/1cdbabf9edd0ea7747efdf6c9ab4e7061b085aa7f9bfc36bb1601563b069/s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7", size = 145287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", size = 83175 }, +] + +[[package]] +name = "setuptools" +version = "82.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584 }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000 }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338 }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909 }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940 }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825 }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705 }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518 }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267 }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797 }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535 }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324 }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803 }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220 }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589 }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213 }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330 }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980 }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424 }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821 }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243 }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361 }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036 }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671 }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059 }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356 }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331 }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590 }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316 }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431 }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555 }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965 }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205 }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209 }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966 }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312 }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967 }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949 }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818 }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626 }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129 }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776 }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879 }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996 }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047 }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947 }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943 }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715 }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857 }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520 }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504 }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282 }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080 }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696 }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121 }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080 }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661 }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645 }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361 }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451 }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814 }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799 }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990 }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292 }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888 }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223 }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981 }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303 }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820 }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203 }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173 }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562 }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828 }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551 }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512 }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400 }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140 }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473 }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056 }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292 }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171 }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, +] From 841a9eefe8518a6aea34f3b7d3e56524e95ca16a Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 17:56:00 +0100 Subject: [PATCH 10/18] Fix build... --- components/.env | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 components/.env diff --git a/components/.env b/components/.env new file mode 100644 index 0000000..0482e3a --- /dev/null +++ b/components/.env @@ -0,0 +1,6 @@ +COMPONENTS=("register_model" "copy_model") + +ORG=atarazana +REGISTRY=quay.io/${ORG} +BASE_IMAGE="quay.io/modh/runtime-images:runtime-minimal-ubi9-python-3.11-20250827-3a59e5e" +TAG=latest From 430cdbb8aabb37466861ad0b5493ff09efd733df Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 18:03:25 +0100 Subject: [PATCH 11/18] Fix build... --- components/register_model/.env | 1 + 1 file changed, 1 insertion(+) create mode 100644 components/register_model/.env diff --git a/components/register_model/.env b/components/register_model/.env new file mode 100644 index 0000000..dd4380c --- /dev/null +++ b/components/register_model/.env @@ -0,0 +1 @@ +TAG=v1.0.3 \ No newline at end of file From 3818409cee4381890aa85b2094061a15d05b94c6 Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 18:35:57 +0100 Subject: [PATCH 12/18] Fix --- .../templates/model-registry.yaml | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/gitops/model-registry/templates/model-registry.yaml b/gitops/model-registry/templates/model-registry.yaml index 971be8d..3e85c2d 100644 --- a/gitops/model-registry/templates/model-registry.yaml +++ b/gitops/model-registry/templates/model-registry.yaml @@ -4,20 +4,17 @@ metadata: name: {{ include "model-registry.fullname" . }} namespace: {{ .Values.registry.namespace }} labels: - {{- include "model-registry.labels" . | nindent 4 }} + {{- include "model-registry.labels" . | nindent 4 }} annotations: openshift.io/description: "" openshift.io/display-name: {{ include "model-registry.fullname" . }} spec: - {{- with .Values.registry.grpc }} grpc: - {{- if .image }} - image: {{ .image }} + {{- if .Values.registry.grpc.image }} + image: {{ .Values.registry.grpc.image }} {{- end }} - {{- if .port }} - port: {{ .port | default 9090 }} - {{- end }} - {{- with .resources }} + port: {{ .Values.registry.grpc.port | default 9090 }} + {{- with .Values.registry.grpc.resources }} resources: limits: cpu: {{ .limits.cpu | default "100m" }} @@ -26,17 +23,13 @@ spec: cpu: {{ .requests.cpu | default "100m" }} memory: {{ .requests.memory | default "256Mi" }} {{- end }} - {{- end }} - {{- with .Values.registry.rest }} rest: - {{- if .image }} - image: {{ .image }} - {{- end }} - {{- if .port }} - port: {{ .port | default 8080 }} + {{- if .Values.registry.rest.image }} + image: {{ .Values.registry.rest.image }} {{- end }} - {{- with .resources }} + port: {{ .Values.registry.rest.port | default 8080 }} + {{- with .Values.registry.rest.resources }} resources: limits: cpu: {{ .limits.cpu | default "100m" }} @@ -45,9 +38,8 @@ spec: cpu: {{ .requests.cpu | default "100m" }} memory: {{ .requests.memory | default "256Mi" }} {{- end }} - serviceRoute: {{ .serviceRoute }} - {{- end }} - + serviceRoute: {{ .Values.registry.rest.serviceRoute | default "disabled" }} + mysql: database: metadb host: {{ include "model-registry.fullname" . }}-db.rhoai-model-registries.svc.cluster.local @@ -55,5 +47,4 @@ spec: key: database-password name: {{ include "model-registry.fullname" . }}-db port: {{ .Values.registryDb.databasePort | default 3306 }} - username: root - \ No newline at end of file + username: root \ No newline at end of file From c82b99d7d7392dbc392cec6e2109fc690e4a5bfb Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 19:50:13 +0100 Subject: [PATCH 13/18] Update to RHOAI 3.2 --- components/register_model/pyproject.toml | 2 +- .../register_model/src/register_model.py | 16 +++- components/register_model/src/test.py | 17 ++++- components/shared/utils.py | 76 +++++++++---------- 4 files changed, 70 insertions(+), 41 deletions(-) diff --git a/components/register_model/pyproject.toml b/components/register_model/pyproject.toml index f51f918..933fb28 100644 --- a/components/register_model/pyproject.toml +++ b/components/register_model/pyproject.toml @@ -9,5 +9,5 @@ dependencies = [ "kfp[kubernetes]==2.13.0", "kubernetes==23.6.0", "load-dotenv==0.1.0", - "model-registry==0.2.21", + "model-registry==0.3.6", ] diff --git a/components/register_model/src/register_model.py b/components/register_model/src/register_model.py index bdf366c..ab23c0e 100644 --- a/components/register_model/src/register_model.py +++ b/components/register_model/src/register_model.py @@ -120,8 +120,22 @@ def _register_model( _log.info(f"Metadata: {metadata}") # Create the model registry object + # ModelRegistry requires is_secure=False and port=80 for HTTP (no TLS) routes _log.info("Creating model registry client...") - registry = ModelRegistry(model_registry_endpoint, author="register_model", user_token=get_token()) + if model_registry_endpoint.startswith("http://"): + registry = ModelRegistry( + model_registry_endpoint, + 80, + author="register_model", + is_secure=False, + user_token=get_token(), + ) + else: + registry = ModelRegistry( + model_registry_endpoint, + author="register_model", + user_token=get_token(), + ) # Register the model _log.info(f"Registering model '{model_name}' version '{model_version}'...") diff --git a/components/register_model/src/test.py b/components/register_model/src/test.py index 243254b..7d6ce9f 100644 --- a/components/register_model/src/test.py +++ b/components/register_model/src/test.py @@ -97,11 +97,26 @@ def main(): '--labels', required=False, default='{}', - help='Labels for the model as a JSON string' + help='Labels for the model as JSON (e.g. {"type":"vision"}) or key=value pairs (e.g. type=vision,accuracy=0.9)' ) args = parser.parse_args() + # Parse labels: accept JSON or key=value,key=value format + labels_str = args.labels + if labels_str and labels_str.strip(): + try: + json.loads(labels_str) + except json.JSONDecodeError: + # Parse key=value,key=value format + labels_dict = {} + for pair in labels_str.split(','): + pair = pair.strip() + if '=' in pair: + k, v = pair.split('=', 1) + labels_dict[k.strip()] = v.strip() + args.labels = json.dumps(labels_dict) + print(f"Model registry name: {args.model_registry_name}") print(f"Istio system namespace: {args.model_registry_namespace}") print(f"Model name: {args.model_name}") diff --git a/components/shared/utils.py b/components/shared/utils.py index 988b339..4c666f5 100644 --- a/components/shared/utils.py +++ b/components/shared/utils.py @@ -1,51 +1,51 @@ -from cProfile import label from kubernetes import client as k8s_cli, config as k8s_conf -# Function that gets the model registry endpoint using a route object -def get_model_registry_endpoint(model_registry_name: str, - namespace: str) -> str: + +def get_model_registry_endpoint(model_registry_name: str, namespace: str) -> str | None: """ - Get the model registry endpoint from the route object in the specified namespace. + Get the model registry REST endpoint from the route in the specified namespace. + + Uses label selectors matching OpenShift AI / ODH model registry operator patterns: + - app.kubernetes.io/name={name} (ModelRegistry CR name) + - app.kubernetes.io/instance={name} or {name}-http or {name}-users (route variants) + Args: - model_registry_name (str): Name of the model registry - namespace (str): Namespace where the model registry route is located + model_registry_name: Name of the model registry (e.g. model-registry-dev) + namespace: Namespace where the model registry is located (e.g. rhoai-model-registries) + Returns: - str: The model registry endpoint URL if found, otherwise None + The model registry endpoint URL (http:// or https://) if found, otherwise None. """ - print(f"Retrieving model registry endpoint for {model_registry_name} in namespace {namespace}") - # Load in-cluster Kubernetes configuration but if it fails, load local configuration try: k8s_conf.load_incluster_config() except k8s_conf.config_exception.ConfigException: k8s_conf.load_kube_config() - # Create Kubernetes API client - api_instance = k8s_cli.CustomObjectsApi() + api = k8s_cli.CustomObjectsApi() + label_namespace_pairs = [ + (f"app.kubernetes.io/name={model_registry_name}", namespace), + (f"app.kubernetes.io/instance={model_registry_name}", namespace), + (f"app.kubernetes.io/instance={model_registry_name}-http", namespace), + (f"app.kubernetes.io/instance={model_registry_name}-users", namespace), + (f"app.kubernetes.io/instance={model_registry_name}", "istio-system"), + (f"app.kubernetes.io/instance={model_registry_name}-users", "istio-system"), + ] - # Selector to find the route by app label - label_selector = f"app.kubernetes.io/name={model_registry_name}" - print(f"Using label selector: {label_selector}") + for label_selector, ns in label_namespace_pairs: + try: + routes = api.list_namespaced_custom_object( + group="route.openshift.io", + version="v1", + namespace=ns, + plural="routes", + label_selector=label_selector, + ) + for route in routes.get("items", []): + host = route.get("spec", {}).get("host", "") + if "-rest" in host or "-http" in host: + scheme = "https" if route.get("spec", {}).get("tls") else "http" + return f"{scheme}://{host}" + except Exception: + continue - try: - # Retrieve the route object - routes = api_instance.list_namespaced_custom_object( - group="route.openshift.io", - version="v1", - namespace=namespace, - plural="routes", - label_selector=label_selector - ) - - # Extract spec.host fields - route_hosts = [route['spec']['host'] for route in routes['items']] - print(f"Found route hosts: {route_hosts}") - - # Return the route host only if it contains "-http" else return None - for route_host in route_hosts: - if "-rest" in route_host: - return f'https://{route_host}' - return None - - except Exception as e: - print(f"Error: {e}") - return None \ No newline at end of file + return None \ No newline at end of file From 2ad5bc607492ad3b70aa234c9c14a8a25ba6b9f7 Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 19:50:58 +0100 Subject: [PATCH 14/18] Update to RHOAI 3.2 --- components/register_model/.env | 2 +- .../src/component_metadata/register_model.yaml | 2 +- components/register_model/src/test.sh | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/components/register_model/.env b/components/register_model/.env index dd4380c..9189a73 100644 --- a/components/register_model/.env +++ b/components/register_model/.env @@ -1 +1 @@ -TAG=v1.0.3 \ No newline at end of file +TAG=v1.0.4 \ No newline at end of file diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index 66f9779..24335b9 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -68,7 +68,7 @@ deploymentSpec: - python3 - -m - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:v1.0.3 + image: quay.io/atarazana/register_model:v1.0.4 pipelineInfo: name: register-model root: diff --git a/components/register_model/src/test.sh b/components/register_model/src/test.sh index faead18..38d7a6a 100755 --- a/components/register_model/src/test.sh +++ b/components/register_model/src/test.sh @@ -3,9 +3,9 @@ # Set PYTHONPATH to the components directory (parent of both shared and register_model) export PYTHONPATH=$(cd "$(dirname "$0")"/../../ && pwd) -# Set default environment variables for model registration -export MODEL_REGISTRY_NAME=${MODEL_REGISTRY_NAME:-"model-registry"} -export ISTIO_SYSTEM_NAMESPACE=${ISTIO_SYSTEM_NAMESPACE:-"istio-system"} +# Set default environment variables for model registration (OpenShift AI default) +export MODEL_REGISTRY_NAME=${MODEL_REGISTRY_NAME:-"model-registry-dev"} +export MODEL_REGISTRY_NAMESPACE=${MODEL_REGISTRY_NAMESPACE:-"rhoai-model-registries"} # Get token using `oc whoami -t` export TOKEN=$(oc whoami -t) @@ -13,8 +13,16 @@ export TOKEN=$(oc whoami -t) # Write the token to a file .token echo $TOKEN > .token -# Run the test script with DEBUG log level with all the arguments -TOKEN_PATH=$(pwd)/.token LOG_LEVEL=DEBUG python test.py $@ +# Run the test script with DEBUG log level. +# Pass registry defaults first; $@ overrides (e.g. for custom model params). +# Example: +# ./test.sh --model-name model1 --model-version 1.0 --model-uri s3://bucket/model1/model.onnx \ +# --model-description "cool model" --model-format-name onnx --model-format-version "1" \ +# --author "Carlos V" --owner "John Doe" --labels "type=vision,accuracy=0.9" +TOKEN_PATH=$(pwd)/.token LOG_LEVEL=DEBUG python test.py \ + --model-registry-name "$MODEL_REGISTRY_NAME" \ + --model-registry-namespace "$MODEL_REGISTRY_NAMESPACE" \ + "$@" # Clean up the token file rm -f .token \ No newline at end of file From 407910c40943027eaab1667899718babc2d1d3e1 Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 19:51:24 +0100 Subject: [PATCH 15/18] Update to RHOAI 3.2 --- components/register_model/uv.lock | 86 +++++-------------------------- 1 file changed, 12 insertions(+), 74 deletions(-) diff --git a/components/register_model/uv.lock b/components/register_model/uv.lock index 2a35f0b..d0e656c 100644 --- a/components/register_model/uv.lock +++ b/components/register_model/uv.lock @@ -105,34 +105,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, ] -[[package]] -name = "boto3" -version = "1.35.54" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, - { name = "jmespath" }, - { name = "s3transfer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/24/e9/52e1db9abfc9ebd1ce8d7a0600f74b226c0b243e78def2b5d59ff8efe594/boto3-1.35.54.tar.gz", hash = "sha256:7d9c359bbbc858a60b51c86328db813353c8bd1940212cdbd0a7da835291c2e1", size = 110991 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/83/81c3d2199f2196493b1f67852e6361a082ca05dc5d976432b86808b7db82/boto3-1.35.54-py3-none-any.whl", hash = "sha256:2d5e160b614db55fbee7981001c54476cb827c441cef65b2fcb2c52a62019909", size = 139158 }, -] - -[[package]] -name = "botocore" -version = "1.35.54" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jmespath" }, - { name = "python-dateutil" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/56/5eacd3dcecdbc36cb5695676c165430282f83cb86ffa75a1a65c34c084c5/botocore-1.35.54.tar.gz", hash = "sha256:131bb59ce59c8a939b31e8e647242d70cf11d32d4529fa4dca01feea1e891a76", size = 12920483 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/cd/e79c87014d0ed371335273cbf8a2bc1fdd6dd2071ba6cb9efedb6e311504/botocore-1.35.54-py3-none-any.whl", hash = "sha256:9cca1811094b6cdc144c2c063a3ec2db6d7c88194b04d4277cd34fc8e3473aff", size = 12708560 }, -] - [[package]] name = "cachetools" version = "5.5.1" @@ -216,15 +188,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 }, ] -[[package]] -name = "eval-type-backport" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830 }, -] - [[package]] name = "frozenlist" version = "1.5.0" @@ -370,18 +333,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, ] -[[package]] -name = "jmespath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, -] - [[package]] name = "kfp" -version = "2.8.0" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -398,7 +352,7 @@ dependencies = [ { name = "tabulate" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/ee/dbf636afac86c7701245ea4f424e2b38038eee51f3731e22f2777e232bbb/kfp-2.8.0.tar.gz", hash = "sha256:06ad584eecbe80318c6cd0231c95a432e91fec56f201def9d511b6e6664235ce", size = 594413 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/8e/cc5418e615c6923914911b43971c04509bf06153b6113e9e64ecdcc9e8c3/kfp-2.13.0.tar.gz", hash = "sha256:bd3e820452157472614217849f7a1cfd9c5d0d3cc7473ace80b6494ca06e8886", size = 269066 } [package.optional-dependencies] kubernetes = [ @@ -417,18 +371,18 @@ sdist = { url = "https://files.pythonhosted.org/packages/78/92/5df7b43e06329132d [[package]] name = "kfp-pipeline-spec" -version = "0.3.0" +version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/63/0a/269a792545cf8a87a30b84bebe69a2b07c483b2887690e8f48c9a91e8060/kfp_pipeline_spec-0.3.0-py3-none-any.whl", hash = "sha256:1db84524a0a2d6c9d36e7e87e6fa0e181bf1ba1513d29dcd54f7b8822e7a52a2", size = 12598 }, + { url = "https://files.pythonhosted.org/packages/21/c4/5a42b32bddae9884b0ab23135f39e49ddb510b56ba9990757c6f873b87ae/kfp_pipeline_spec-0.6.0-py3-none-any.whl", hash = "sha256:9e319b62eaa54c6790a96f796d34f071458c9cae9585c662629eb090688555a7", size = 9081 }, ] [[package]] name = "kfp-server-api" -version = "2.0.5" +version = "2.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -436,7 +390,7 @@ dependencies = [ { name = "six" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/4b/1b1c9286047e78ebc9de2a9d4d43921d6efb5e6550fdc38229127a03aa53/kfp-server-api-2.0.5.tar.gz", hash = "sha256:c9cfbf0e87271d3bfe96e5ecc9ffbdd6ab566bc1c9a9ddc2a39d7698a16e26ff", size = 63401 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/5c/10c7cd96cee27da45a1b90d2a95f7ec76876673fdcb0c391110ec7e75089/kfp_server_api-2.4.0.tar.gz", hash = "sha256:9d71ce49fc6757af14b052cc47e4cb531cb4e4584c2ea76ec02b9197ee9a674f", size = 83953 } [[package]] name = "kubernetes" @@ -473,20 +427,19 @@ wheels = [ [[package]] name = "model-registry" -version = "0.2.21" +version = "0.3.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "aiohttp-retry" }, - { name = "eval-type-backport" }, { name = "nest-asyncio" }, { name = "pydantic" }, { name = "python-dateutil" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/b7/0254b6d660b46b1e8f74e7b8f5b0d6c5ae4b083c4c294649f56bb60671ad/model_registry-0.2.21.tar.gz", hash = "sha256:07eb145fedf519c16cdd9151f49d53fa6b10b68dfd81a92e67f4c9e2b7f6c244", size = 72602 } +sdist = { url = "https://files.pythonhosted.org/packages/bb/e8/790640c40b9c4a6ba792df97596d6989e4e2e52e3fba1c22f36369b2a73c/model_registry-0.3.6.tar.gz", hash = "sha256:79d3bf95a65a0b01d84e6ff5a9ba0d0920a69042bc2ea45cb573cdc7c571fcff", size = 105137 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/33/737f428a7d8410bef207746271c4a874a5697b78cb685ff16e689ee21c4d/model_registry-0.2.21-py3-none-any.whl", hash = "sha256:1546fb3b9f888a01b34307d330078241bae1244a123a83b008c85e9384e29205", size = 143552 }, + { url = "https://files.pythonhosted.org/packages/3e/49/f025399a9cff506ee7821f98e2fe7dc94ab475002493a16a82ecd7594f09/model_registry-0.3.6-py3-none-any.whl", hash = "sha256:b7b5ad080cb982db4442107d818cd47d50cea4361552cdd030b247bc039150b6", size = 216727 }, ] [[package]] @@ -739,8 +692,6 @@ name = "register-model" version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "boto3" }, - { name = "botocore" }, { name = "kfp", extra = ["kubernetes"] }, { name = "kubernetes" }, { name = "load-dotenv" }, @@ -749,12 +700,11 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "boto3", specifier = "==1.35.54" }, - { name = "botocore", specifier = "==1.35.54" }, - { name = "kfp", extras = ["kubernetes"], specifier = "==2.8.0" }, + { name = "kfp", specifier = "==2.13.0" }, + { name = "kfp", extras = ["kubernetes"], specifier = "==2.13.0" }, { name = "kubernetes", specifier = "==23.6.0" }, { name = "load-dotenv", specifier = "==0.1.0" }, - { name = "model-registry", specifier = "==0.2.21" }, + { name = "model-registry", specifier = "==0.3.6" }, ] [[package]] @@ -809,18 +759,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 }, ] -[[package]] -name = "s3transfer" -version = "0.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/1cdbabf9edd0ea7747efdf6c9ab4e7061b085aa7f9bfc36bb1601563b069/s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7", size = 145287 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", size = 83175 }, -] - [[package]] name = "setuptools" version = "75.8.0" From deab750986a8200d77efef1010c48c8c369d603b Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 20:02:44 +0100 Subject: [PATCH 16/18] 1.0.4 --- .../register_model/src/component_metadata/register_model.yaml | 2 +- components/register_model/src/register_model.py | 2 +- components/register_model/src/runtime-requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index 24335b9..40c6052 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -62,7 +62,7 @@ deploymentSpec: - -c - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ - \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.2.14'\ + \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.3.6'\ \ 'kubernetes==23.6.0' 'load_dotenv==0.1.0' 'botocore==1.35.54' 'boto3==1.35.54'\ \ && \"$0\" \"$@\"\n" - python3 diff --git a/components/register_model/src/register_model.py b/components/register_model/src/register_model.py index ab23c0e..f31f403 100644 --- a/components/register_model/src/register_model.py +++ b/components/register_model/src/register_model.py @@ -24,7 +24,7 @@ TAG=os.environ.get("TAG", f"latest") TARGET_IMAGE=f"{REGISTRY}/{COMPONENT_NAME}:{TAG}" -MODEL_REGISTRY_PIP_VERSION="0.2.14" +MODEL_REGISTRY_PIP_VERSION="0.3.6" K8S_PIP_VERSION="23.6.0" LOAD_DOTENV_PIP_VERSION="0.1.0" BOTOCORE_PIP_VERSION="1.35.54" diff --git a/components/register_model/src/runtime-requirements.txt b/components/register_model/src/runtime-requirements.txt index 7cf1277..38c1a36 100644 --- a/components/register_model/src/runtime-requirements.txt +++ b/components/register_model/src/runtime-requirements.txt @@ -3,4 +3,4 @@ boto3==1.35.54 botocore==1.35.54 kubernetes==23.6.0 load_dotenv==0.1.0 -model_registry==0.2.14 \ No newline at end of file +model_registry==0.3.6 \ No newline at end of file From ad1d15b4d0bca1df6049c06a4d920f87fac1e7f6 Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 20:32:09 +0100 Subject: [PATCH 17/18] 1.0.5 no packages_to_install --- components/Containerfile | 2 +- components/register_model/.env | 2 +- components/register_model/requirements.txt | 5 +---- .../src/component_metadata/register_model.yaml | 9 +-------- components/register_model/src/register_model.py | 15 +++++---------- .../register_model/src/runtime-requirements.txt | 5 ----- 6 files changed, 9 insertions(+), 29 deletions(-) diff --git a/components/Containerfile b/components/Containerfile index 29d5740..f31a1b2 100644 --- a/components/Containerfile +++ b/components/Containerfile @@ -12,7 +12,7 @@ WORKDIR /usr/local/src/kfp/components COPY ${COMPONENT_NAME}/src/runtime-requirements.txt runtime-requirements.txt RUN pip install --no-cache-dir -r runtime-requirements.txt -RUN pip install --no-cache-dir kfp==2.8.0 +RUN pip install --no-cache-dir kfp==2.13.0 COPY ${COMPONENT_NAME}/src/ . COPY shared ./shared diff --git a/components/register_model/.env b/components/register_model/.env index 9189a73..e1a80f5 100644 --- a/components/register_model/.env +++ b/components/register_model/.env @@ -1 +1 @@ -TAG=v1.0.4 \ No newline at end of file +TAG=v1.0.5 \ No newline at end of file diff --git a/components/register_model/requirements.txt b/components/register_model/requirements.txt index e9da19d..264e724 100644 --- a/components/register_model/requirements.txt +++ b/components/register_model/requirements.txt @@ -1,7 +1,4 @@ kfp[kubernetes]==2.8.0 -model_registry==0.2.21 -boto3==1.35.54 -botocore==1.35.54 +model_registry==0.3.6 kubernetes==23.6.0 - load_dotenv==0.1.0 diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index 40c6052..653485f 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -58,17 +58,10 @@ deploymentSpec: - --function_to_execute - register_model command: - - sh - - -c - - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ - \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ - \ python3 -m pip install --quiet --no-warn-script-location 'model_registry==0.3.6'\ - \ 'kubernetes==23.6.0' 'load_dotenv==0.1.0' 'botocore==1.35.54' 'boto3==1.35.54'\ - \ && \"$0\" \"$@\"\n" - python3 - -m - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:v1.0.4 + image: quay.io/atarazana/register_model:v1.0.5 pipelineInfo: name: register-model root: diff --git a/components/register_model/src/register_model.py b/components/register_model/src/register_model.py index f31f403..64fa191 100644 --- a/components/register_model/src/register_model.py +++ b/components/register_model/src/register_model.py @@ -24,11 +24,11 @@ TAG=os.environ.get("TAG", f"latest") TARGET_IMAGE=f"{REGISTRY}/{COMPONENT_NAME}:{TAG}" -MODEL_REGISTRY_PIP_VERSION="0.3.6" -K8S_PIP_VERSION="23.6.0" -LOAD_DOTENV_PIP_VERSION="0.1.0" -BOTOCORE_PIP_VERSION="1.35.54" -BOTO3_PIP_VERSION="1.35.54" +# MODEL_REGISTRY_PIP_VERSION="0.3.6" +# K8S_PIP_VERSION="23.6.0" +# LOAD_DOTENV_PIP_VERSION="0.1.0" +# BOTOCORE_PIP_VERSION="1.35.54" +# BOTO3_PIP_VERSION="1.35.54" # Allowed log levels VALID_LOG_LEVELS = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} @@ -192,11 +192,6 @@ def _register_model( @dsl.component( base_image=BASE_IMAGE, target_image=TARGET_IMAGE, - packages_to_install=[f"model_registry=={MODEL_REGISTRY_PIP_VERSION}", - f"kubernetes=={K8S_PIP_VERSION}", - f"load_dotenv=={LOAD_DOTENV_PIP_VERSION}", - f"botocore=={BOTOCORE_PIP_VERSION}", - f"boto3=={BOTO3_PIP_VERSION}"], ) def register_model( model_registry_name: str, # Name of the model registry diff --git a/components/register_model/src/runtime-requirements.txt b/components/register_model/src/runtime-requirements.txt index 38c1a36..42f8a81 100644 --- a/components/register_model/src/runtime-requirements.txt +++ b/components/register_model/src/runtime-requirements.txt @@ -1,6 +1 @@ # Generated by KFP. -boto3==1.35.54 -botocore==1.35.54 -kubernetes==23.6.0 -load_dotenv==0.1.0 -model_registry==0.3.6 \ No newline at end of file From dc95884c52cecaf163f40601fe72eeae7d56389f Mon Sep 17 00:00:00 2001 From: cvicens Date: Tue, 24 Feb 2026 21:25:27 +0100 Subject: [PATCH 18/18] 1.0.6 with all the requirements --- components/Containerfile | 10 +++++++--- components/register_model/.env | 2 +- components/register_model/pyproject.toml | 2 +- components/register_model/requirements.txt | 3 ++- .../src/component_metadata/register_model.yaml | 2 +- components/register_model/src/test.sh | 5 +++-- components/run-component.sh | 9 ++++++++- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/components/Containerfile b/components/Containerfile index f31a1b2..0c323b4 100644 --- a/components/Containerfile +++ b/components/Containerfile @@ -9,11 +9,15 @@ ARG COMPONENT_NAME WORKDIR /usr/local/src/kfp/components -COPY ${COMPONENT_NAME}/src/runtime-requirements.txt runtime-requirements.txt +# Install uv +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -RUN pip install --no-cache-dir -r runtime-requirements.txt -RUN pip install --no-cache-dir kfp==2.13.0 +# Install dependencies into the base image's default Python (/opt/app-root/bin/python) +COPY ${COMPONENT_NAME}/requirements.txt component-requirements.txt +USER root +RUN uv pip install -r component-requirements.txt --python /opt/app-root/bin/python +# Copy component source and shared COPY ${COMPONENT_NAME}/src/ . COPY shared ./shared diff --git a/components/register_model/.env b/components/register_model/.env index e1a80f5..6feeaed 100644 --- a/components/register_model/.env +++ b/components/register_model/.env @@ -1 +1 @@ -TAG=v1.0.5 \ No newline at end of file +TAG=v1.0.6 \ No newline at end of file diff --git a/components/register_model/pyproject.toml b/components/register_model/pyproject.toml index 933fb28..d3baeeb 100644 --- a/components/register_model/pyproject.toml +++ b/components/register_model/pyproject.toml @@ -3,7 +3,7 @@ name = "register-model" version = "0.1.0" description = "Add your description here" readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.11" dependencies = [ "kfp==2.13.0", "kfp[kubernetes]==2.13.0", diff --git a/components/register_model/requirements.txt b/components/register_model/requirements.txt index 264e724..f8a17ff 100644 --- a/components/register_model/requirements.txt +++ b/components/register_model/requirements.txt @@ -1,4 +1,5 @@ -kfp[kubernetes]==2.8.0 +kfp==2.13.0 +kfp[kubernetes]==2.13.0 model_registry==0.3.6 kubernetes==23.6.0 load_dotenv==0.1.0 diff --git a/components/register_model/src/component_metadata/register_model.yaml b/components/register_model/src/component_metadata/register_model.yaml index 653485f..71f687a 100644 --- a/components/register_model/src/component_metadata/register_model.yaml +++ b/components/register_model/src/component_metadata/register_model.yaml @@ -61,7 +61,7 @@ deploymentSpec: - python3 - -m - kfp.dsl.executor_main - image: quay.io/atarazana/register_model:v1.0.5 + image: quay.io/atarazana/register_model:v1.0.6 pipelineInfo: name: register-model root: diff --git a/components/register_model/src/test.sh b/components/register_model/src/test.sh index 38d7a6a..6fde186 100755 --- a/components/register_model/src/test.sh +++ b/components/register_model/src/test.sh @@ -1,7 +1,8 @@ #!/bin/bash -# Set PYTHONPATH to the components directory (parent of both shared and register_model) -export PYTHONPATH=$(cd "$(dirname "$0")"/../../ && pwd) +# Set PYTHONPATH: script dir for container (shared/ is sibling); ../../ for host (shared/ is in components/) +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +export PYTHONPATH=$([ -d "$SCRIPT_DIR/shared" ] && echo "$SCRIPT_DIR" || echo "$SCRIPT_DIR:$(cd "$SCRIPT_DIR/../.." && pwd)") # Set default environment variables for model registration (OpenShift AI default) export MODEL_REGISTRY_NAME=${MODEL_REGISTRY_NAME:-"model-registry-dev"} diff --git a/components/run-component.sh b/components/run-component.sh index 4262a7e..bb7d04f 100755 --- a/components/run-component.sh +++ b/components/run-component.sh @@ -21,6 +21,13 @@ echo "BASE_IMAGE: ${BASE_IMAGE}" echo "REGISTRY: ${REGISTRY}" echo "TAG: ${TAG}" +# Mount kubeconfig so oc/kubectl work inside the container +KUBECONFIG_PATH=${KUBECONFIG:-$HOME/.kube/config} +MOUNT_ARGS=() +if [ -n "$KUBECONFIG_PATH" ] && [ -f "${KUBECONFIG_PATH%%:*}" ]; then + MOUNT_ARGS=(-v "${KUBECONFIG_PATH%%:*}:/tmp/kubeconfig:ro" -e KUBECONFIG=/tmp/kubeconfig) +fi + # Run the component image -podman run -it --rm localhost/${COMPONENT_NAME}:${TAG} bash +podman run -it --rm "${MOUNT_ARGS[@]}" localhost/${COMPONENT_NAME}:${TAG} bash # podman run -it --rm --entrypoint bash localhost/${COMPONENT_NAME}:latest