diff --git a/.gcloudignore b/.gcloudignore deleted file mode 100644 index c1036125..00000000 --- a/.gcloudignore +++ /dev/null @@ -1,3 +0,0 @@ -.venv -terraform -.git diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9d140c04..888c7fae 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -15,6 +15,7 @@ jobs: with: environment: beta secrets: inherit + build_prod: name: Build production needs: [build_beta] @@ -22,6 +23,7 @@ jobs: with: environment: prod secrets: inherit + deploy_beta: name: Deploy beta needs: [build_beta] @@ -29,6 +31,7 @@ jobs: with: environment: beta secrets: inherit + deploy_prod: name: Deploy production needs: [build_prod, deploy_beta] @@ -36,3 +39,12 @@ jobs: with: environment: prod secrets: inherit + + publish_clients: + name: Publish API clients + needs: [deploy_prod] + uses: ./.github/workflows/publish-clients.reusable.yml + with: + environment: prod + secrets: + PYPI_TOKEN: ${{ secrets.PYPI }} diff --git a/.github/workflows/gcp-build.reusable.yml b/.github/workflows/gcp-build.reusable.yml index 8e334804..22e46bf5 100644 --- a/.github/workflows/gcp-build.reusable.yml +++ b/.github/workflows/gcp-build.reusable.yml @@ -1,4 +1,4 @@ -name: Reusable deploy to gcp workflow +name: Reusable build workflow on: workflow_call: @@ -6,97 +6,130 @@ on: environment: required: true type: string - description: 'The environment to deploy to (e.g., beta, prod)' + description: 'The environment to build for (e.g., beta, prod)' env: - TF_BACKEND_bucket: ${{ vars.PROJECT_ID }}-state - #TF_VAR_whatever will be picked up as terraform variables. - TF_VAR_org_id: ${{ secrets.ORG_ID }} - TF_VAR_billing_account: ${{ secrets.BILLING_ACCOUNT }} - TF_VAR_github_repo_owner_id: ${{ github.repository_owner_id }} - TF_VAR_github_repo: ${{ github.repository }} - TF_VAR_project_id: ${{ vars.PROJECT_ID }} - TF_VAR_region: ${{ vars.REGION }} - TF_VAR_full_container_tag: ${{ github.sha }} - TF_VAR_simulation_container_tag: ${{ github.sha }} - TF_VAR_container_tag: ${{ github.sha }} - BUILD_TAG: ${{ github.run_id }}.${{ github.run_number }}.${{ github.run_attempt }} - COMMIT_TAG: ${{ github.sha }} + PROJECT_ID: ${{ vars.PROJECT_ID }} + REGION: ${{ vars.REGION }} + REPO: api-v2 + jobs: - #api build steps are separated so they can run in parallel. build_simulation_api_image: - # Any runner supporting Node 20 or newer + name: Build simulation API image runs-on: ubuntu-latest environment: ${{ inputs.environment }} - name: Build simulation API image permissions: contents: "read" - # Required to auth against gcp id-token: "write" steps: - - name: checkout repo + - name: Checkout repo uses: actions/checkout@v4 + - uses: "google-github-actions/auth@v2" with: workload_identity_provider: "${{ vars._GITHUB_IDENTITY_POOL_PROVIDER_NAME }}" service_account: "builder@${{ vars.PROJECT_ID }}.iam.gserviceaccount.com" - - name: "Set up Cloud SDK" + + - name: Set up Cloud SDK uses: "google-github-actions/setup-gcloud@v2" + + - name: Configure Docker for Artifact Registry + run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push simulation API + uses: docker/build-push-action@v5 with: - version: ">= 363.0.0" - - name: Build application - run: make -f Makefile.deploy publish-simulation-api-docker TAG=${{ github.sha }} PROJECT_ID=${{ vars.PROJECT_ID }} LOG_DIR=gs://${{ vars.PROJECT_ID }}-buildlogs + context: . + file: projects/policyengine-api-simulation/Dockerfile + push: true + tags: | + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-simulation:${{ github.sha }} + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-simulation:latest + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 build_full_api_image: - # Any runner supporting Node 20 or newer + name: Build full API image runs-on: ubuntu-latest environment: ${{ inputs.environment }} - name: Build full API image - # Add "id-token" with the intended permissions. permissions: contents: "read" - #required to auth against GCP id-token: "write" steps: - - name: checkout repo + - name: Checkout repo uses: actions/checkout@v4 + - uses: "google-github-actions/auth@v2" with: workload_identity_provider: "${{ vars._GITHUB_IDENTITY_POOL_PROVIDER_NAME }}" service_account: "builder@${{ vars.PROJECT_ID }}.iam.gserviceaccount.com" - - name: "Set up Cloud SDK" + + - name: Set up Cloud SDK uses: "google-github-actions/setup-gcloud@v2" + + - name: Configure Docker for Artifact Registry + run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push full API + uses: docker/build-push-action@v5 with: - version: ">= 363.0.0" - - name: Build application - run: make -f Makefile.deploy publish-full-api-docker TAG=${{ github.sha }} PROJECT_ID=${{ vars.PROJECT_ID }} LOG_DIR=gs://${{ vars.PROJECT_ID }}-buildlogs + context: . + file: projects/policyengine-api-full/Dockerfile + push: true + tags: | + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-full:${{ github.sha }} + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-full:latest + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 build_tagger_api_image: - # Any runner supporting Node 20 or newer + name: Build tagger API image runs-on: ubuntu-latest environment: ${{ inputs.environment }} - name: Build tagger API image - # Add "id-token" with the intended permissions. permissions: contents: "read" - #required to auth against GCP id-token: "write" steps: - - name: checkout repo + - name: Checkout repo uses: actions/checkout@v4 + - uses: "google-github-actions/auth@v2" with: workload_identity_provider: "${{ vars._GITHUB_IDENTITY_POOL_PROVIDER_NAME }}" service_account: "builder@${{ vars.PROJECT_ID }}.iam.gserviceaccount.com" - - name: "Set up Cloud SDK" + + - name: Set up Cloud SDK uses: "google-github-actions/setup-gcloud@v2" + + - name: Configure Docker for Artifact Registry + run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push tagger API + uses: docker/build-push-action@v5 with: - version: ">= 363.0.0" - - name: Build application - run: make -f Makefile.deploy publish-tagger-api-docker TAG=${{ github.sha }} PROJECT_ID=${{ vars.PROJECT_ID }} LOG_DIR=gs://${{ vars.PROJECT_ID }}-buildlogs + context: . + file: projects/policyengine-api-tagger/Dockerfile + push: true + tags: | + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-tagger:${{ github.sha }} + ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO }}/policyengine-api-tagger:latest + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 \ No newline at end of file diff --git a/.github/workflows/gcp-deploy.reusable.yml b/.github/workflows/gcp-deploy.reusable.yml index 626f16d2..206baf10 100644 --- a/.github/workflows/gcp-deploy.reusable.yml +++ b/.github/workflows/gcp-deploy.reusable.yml @@ -1,4 +1,4 @@ -name: Reusable deploy to gcp workflow +name: Reusable deploy workflow on: workflow_call: @@ -10,73 +10,160 @@ on: env: TF_BACKEND_bucket: ${{ vars.PROJECT_ID }}-state - #TF_VAR_whatever will be picked up as terraform variables. - TF_VAR_org_id: ${{ secrets.ORG_ID }} - TF_VAR_billing_account: ${{ secrets.BILLING_ACCOUNT }} - TF_VAR_github_repo_owner_id: ${{ github.repository_owner_id }} - TF_VAR_github_repo: ${{ github.repository }} TF_VAR_project_id: ${{ vars.PROJECT_ID }} TF_VAR_region: ${{ vars.REGION }} TF_VAR_full_container_tag: ${{ github.sha }} TF_VAR_simulation_container_tag: ${{ github.sha }} TF_VAR_tagger_container_tag: ${{ github.sha }} - TF_VAR_hugging_face_token: ${{ secrets.HUGGING_FACE_TOKEN }} - TF_VAR_slack_notification_channel_name: ${{ vars.SLACK_NOTIFICATION_CHANNEL }} - BUILD_TAG: ${{ github.run_id }}.${{ github.run_number }}.${{ github.run_attempt }} - COMMIT_TAG: ${{ github.sha }} + TF_VAR_commit_url: https://github.com/${{ github.repository }}/commit/${{ github.sha }} + jobs: deploy: - runs-on: ubuntu-latest name: Deploy + runs-on: ubuntu-latest outputs: - #This is required for the test step so it can authenticate and connect to - #the beta endpoint full_api_url: ${{ steps.deploy_infra.outputs.full_api_url }} simulation_api_url: ${{ steps.deploy_infra.outputs.simulation_api_url }} + us_model_version: ${{ steps.deploy_infra.outputs.us_model_version }} + uk_model_version: ${{ steps.deploy_infra.outputs.uk_model_version }} environment: ${{ inputs.environment }} env: TF_VAR_stage: ${{ inputs.environment }} - TF_VAR_is_prod: ${{ inputs.environment == 'prod' && (vars.IS_DEV_FORK == 'false') }} + TF_VAR_is_prod: ${{ inputs.environment == 'prod' }} permissions: contents: "read" - #required to auth against GCP id-token: "write" steps: - name: Checkout repo uses: actions/checkout@v4 + - name: Authenticate as deploy SA in GCP uses: "google-github-actions/auth@v2" with: workload_identity_provider: "${{ vars._GITHUB_IDENTITY_POOL_PROVIDER_NAME }}" service_account: "deploy@${{ vars.PROJECT_ID }}.iam.gserviceaccount.com" + - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v2 + - uses: hashicorp/setup-terraform@v3 + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.13" + - name: Install uv - uses: astral-sh/setup-uv@v5 - - name: Create/update GCP project - run: make -f Makefile.deploy deploy-project - - name: Deploy services into the GCP project + uses: astral-sh/setup-uv@v3 + + - name: Extract package versions + id: versions + run: | + US_VERSION=$(grep -A1 'name = "policyengine-us"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') + UK_VERSION=$(grep -A1 'name = "policyengine-uk"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "us_version=$US_VERSION" >> $GITHUB_OUTPUT + echo "uk_version=$UK_VERSION" >> $GITHUB_OUTPUT + echo "TF_VAR_policyengine_us_package_version=$US_VERSION" >> $GITHUB_ENV + echo "TF_VAR_policyengine_uk_package_version=$UK_VERSION" >> $GITHUB_ENV + + - name: Create terraform backend config + run: | + cat > deployment/terraform/infra/backend.tf < deployment/terraform/infra/terraform.tfvars < terraform_output.json + FULL_API_URL=$(cat terraform_output.json | jq -r '.full_api_url.value // empty') + SIMULATION_API_URL=$(cat terraform_output.json | jq -r '.simulation_api_url.value // empty') + + # Extract model versions from release_metadata + US_MODEL_VERSION=$(cat terraform_output.json | jq -r '.release_metadata.value.models.us // empty') + UK_MODEL_VERSION=$(cat terraform_output.json | jq -r '.release_metadata.value.models.uk // empty') + + # If outputs are not available from terraform, construct them + if [ -z "$FULL_API_URL" ]; then + FULL_API_URL="https://full-api-${{ vars.REGION }}-uc.a.run.app" + fi + if [ -z "$SIMULATION_API_URL" ]; then + SIMULATION_API_URL="https://api-simulation-${{ vars.REGION }}-uc.a.run.app" + fi + + # If model versions are not available from terraform, use the ones from package extraction + if [ -z "$US_MODEL_VERSION" ]; then + US_MODEL_VERSION="${{ steps.versions.outputs.us_version }}" + fi + if [ -z "$UK_MODEL_VERSION" ]; then + UK_MODEL_VERSION="${{ steps.versions.outputs.uk_version }}" + fi + echo "full_api_url=${FULL_API_URL}" >> "$GITHUB_OUTPUT" - echo "exporting simulation_api_url ${SIMULATION_API_URL}" echo "simulation_api_url=${SIMULATION_API_URL}" >> "$GITHUB_OUTPUT" + echo "us_model_version=${US_MODEL_VERSION}" >> "$GITHUB_OUTPUT" + echo "uk_model_version=${UK_MODEL_VERSION}" >> "$GITHUB_OUTPUT" + + - name: Tag API versions in metadata bucket + working-directory: deployment/terraform/infra + run: | + # Get the metadata bucket name from terraform output + METADATA_BUCKET=$(terraform output -raw metadata_bucket_name) + + # Get the release metadata JSON + RELEASE_METADATA=$(terraform output -json release_metadata) + + # Upload metadata files to GCS bucket + # Upload live.json + echo "$RELEASE_METADATA" | gcloud storage cp - "gs://${METADATA_BUCKET}/live.json" + + # Upload version-tagged metadata for US model + US_VERSION="${{ steps.versions.outputs.us_version }}" + echo "$RELEASE_METADATA" | gcloud storage cp - "gs://${METADATA_BUCKET}/us.${US_VERSION}.json" + + # Upload version-tagged metadata for UK model + UK_VERSION="${{ steps.versions.outputs.uk_version }}" + echo "$RELEASE_METADATA" | gcloud storage cp - "gs://${METADATA_BUCKET}/uk.${UK_VERSION}.json" + + echo "Tagged API versions: US=${US_VERSION}, UK=${UK_VERSION}" integ_test: - needs: [deploy] name: Run integration test + needs: [deploy] runs-on: ubuntu-latest environment: ${{ inputs.environment }} @@ -87,18 +174,22 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Install uv - uses: astral-sh/setup-uv@v5 - - name: Create uv venv - run: | - uv venv -p 3.13 - uv pip install rich + uses: astral-sh/setup-uv@v3 + - name: Authenticate as tester SA in GCP uses: "google-github-actions/auth@v2" with: workload_identity_provider: "${{ vars._GITHUB_IDENTITY_POOL_PROVIDER_NAME }}" service_account: "tester@${{ vars.PROJECT_ID }}.iam.gserviceaccount.com" - - name: Auth as tester SA in GCP for full API + + - name: Auth as tester SA for full API id: get-full-id-token uses: "google-github-actions/auth@v2" with: @@ -107,7 +198,8 @@ jobs: token_format: "id_token" id_token_audience: ${{ needs.deploy.outputs.full_api_url }} id_token_include_email: true - - name: Auth as tester SA in GCP for simulation API + + - name: Auth as tester SA for simulation API id: get-simulation-id-token uses: "google-github-actions/auth@v2" with: @@ -116,9 +208,25 @@ jobs: token_format: "id_token" id_token_audience: ${{ needs.deploy.outputs.simulation_api_url }} id_token_include_email: true - - name: Mask ID token to prevent accidental leak - run: echo "::add-mask::${{steps.get-id-token.outputs.id_token}}" - - name: Run integration tests against deployed API + + - name: Mask ID tokens + run: | + echo "::add-mask::${{steps.get-full-id-token.outputs.id_token}}" + echo "::add-mask::${{steps.get-simulation-id-token.outputs.id_token}}" + + - name: Generate API clients + run: | + ./scripts/generate-clients.sh + + - name: Run integration tests run: | - . .venv/bin/activate - make -f Makefile.deploy integ-test FULL_API_ACCESS_TOKEN=${{steps.get-full-id-token.outputs.id_token}} FULL_API_URL=${{needs.deploy.outputs.full_api_url }} SIMULATION_API_ACCESS_TOKEN=${{steps.get-simulation-id-token.outputs.id_token}} SIMULATION_API_URL=${{needs.deploy.outputs.simulation_api_url}} + cd projects/policyengine-apis-integ + uv sync --extra test + uv run pytest tests/ -v + env: + full_integ_test_access_token: ${{ steps.get-full-id-token.outputs.id_token }} + full_integ_test_base_url: ${{ needs.deploy.outputs.full_api_url }} + simulation_integ_test_access_token: ${{ steps.get-simulation-id-token.outputs.id_token }} + simulation_integ_test_base_url: ${{ needs.deploy.outputs.simulation_api_url }} + workflow_integ_test_project_id: ${{ vars.PROJECT_ID }} + workflow_integ_test_us_model_version: ${{ needs.deploy.outputs.us_model_version }} \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 66476914..015232b2 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,35 +1,145 @@ -name: Pull request +name: PR checks on: pull_request: + branches: [main] jobs: - build: + test: name: Test - # Any runner supporting Node 20 or newer runs-on: ubuntu-latest + strategy: + matrix: + service: [api-full, api-simulation, api-tagger] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Install uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Install dependencies + run: | + cd projects/policyengine-${{ matrix.service }} + uv sync --extra test + + - name: Run tests + run: | + cd projects/policyengine-${{ matrix.service }} + uv run pytest tests/ -v - # Add "id-token" with the intended permissions. - permissions: - contents: "read" + lint: + name: Lint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Install uv + uses: astral-sh/setup-uv@v3 + + - name: Install ruff + run: uv tool install ruff + + - name: Run ruff format check + run: | + for dir in projects/*/src libs/*/src; do + if [ -d "$dir" ]; then + echo "Checking format in $dir..." + uv run ruff format --check $dir + fi + done + + docker-build: + name: Docker build + needs: [test, lint] # Only run if tests and linting pass + runs-on: ubuntu-latest + strategy: + matrix: + service: [api-full, api-simulation, api-tagger] steps: - - name: checkout repo - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: projects/policyengine-${{ matrix.service }}/Dockerfile + push: false + tags: policyengine-${{ matrix.service }}:test + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 + + test-integration: + name: Test integration + needs: docker-build # Only run if docker builds succeed + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + - name: Install uv - uses: astral-sh/setup-uv@v5 - # Then create a uv venv 3.13 and activate it - - name: Create and activate uv venv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Generate API clients run: | - uv venv -p 3.13 - - name: Build application + ./scripts/generate-clients.sh + + - name: Start services run: | - . .venv/bin/activate - make build - - name: Run tests + docker compose -f deployment/docker-compose.yml up -d + # Wait for services to be ready + sleep 10 + # Check services are responding + for i in {1..30}; do + if curl -f http://localhost:8081/ping/alive && curl -f http://localhost:8082/ping/alive; then + echo "Services are ready!" + break + fi + echo "Waiting for services... (attempt $i/30)" + sleep 2 + done + + - name: Run integration tests + run: | + cd projects/policyengine-apis-integ + uv sync --extra test + # Run tests that don't require GCP credentials + uv run pytest tests/ -v -m "not requires_gcp" + + - name: Show service logs on failure + if: failure() run: | - . .venv/bin/activate - make test - - name: Check docker images + docker compose -f deployment/docker-compose.yml logs + + - name: Stop services + if: always() run: | - make docker-check + docker compose -f deployment/docker-compose.yml down \ No newline at end of file diff --git a/.github/workflows/publish-clients.reusable.yml b/.github/workflows/publish-clients.reusable.yml new file mode 100644 index 00000000..0a773ef6 --- /dev/null +++ b/.github/workflows/publish-clients.reusable.yml @@ -0,0 +1,41 @@ +name: Reusable publish clients workflow + +on: + workflow_call: + inputs: + environment: + required: true + type: string + description: 'The environment that was deployed (e.g., beta, prod)' + secrets: + PYPI_TOKEN: + required: true + description: 'PyPI API token for publishing packages' + +jobs: + publish: + name: Publish API clients + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Install uv + uses: astral-sh/setup-uv@v3 + + - name: Generate API clients + run: | + ./scripts/generate-clients.sh + + - name: Publish clients to PyPI + env: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + run: | + ./scripts/publish-clients.sh \ No newline at end of file diff --git a/.github/workflows/dependency-updater.yml b/.github/workflows/update-dependencies.yml similarity index 91% rename from .github/workflows/dependency-updater.yml rename to .github/workflows/update-dependencies.yml index 9cb5a346..3d971e55 100644 --- a/.github/workflows/dependency-updater.yml +++ b/.github/workflows/update-dependencies.yml @@ -25,15 +25,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.POLICYENGINE_BOT_TOKEN }} - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: "3.11" - - - name: Set up poetry - run: uv pip install poetry --system + python-version: "3.13" - name: Update dependencies id: update diff --git a/.gitignore b/.gitignore index 9f435eb1..354d379d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ apply.tfvars backend.tfvars CLAUDE.md .vscode +deployment/terraform/*/auto.tfvars diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 2d530ddd..00000000 --- a/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -#as per uv documentation -FROM python:3.13-slim -ARG SERVICE_NAME=UNSET_SERVICE_NAME -ARG MODULE_NAME=UNSET_MODULE_NAME -ARG WORKER_COUNT=1 -COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ - -ENV ENVIRONMENT="production" \ - JWT_ISSUER=https://your_production_issuer/ \ - JWT_AUDIENCE=https://your_production_api/ \ - OT_SERVICE_NAME=${SERVICE_NAME}\ - OT_SERVICE_INSTANCE_ID=instance - -WORKDIR /app -COPY . . -WORKDIR /app/projects/${SERVICE_NAME} -RUN uv sync --locked - -EXPOSE 8080 -ENV MODULE_NAME=$MODULE_NAME -ENV WORKER_COUNT=$WORKER_COUNT -CMD cd src && uv run uvicorn $MODULE_NAME:app --host 0.0.0.0 --port 8080 --workers $WORKER_COUNT diff --git a/Makefile b/Makefile index e35db257..092ec74a 100644 --- a/Makefile +++ b/Makefile @@ -1,210 +1,375 @@ -LIBDIRS := libs/policyengine-fastapi -SERVICEDIRS := projects/policyengine-api-full projects/policyengine-api-simulation projects/policyengine-api-tagger -SUBDIRS := $(LIBDIRS) $(SERVICEDIRS) +# Simplified Makefile using docker-compose +.PHONY: help dev up down build test deploy clean logs format check terraform-deploy -# Helper for pretty output -HELPER := python3 scripts/ensure_rich.py && python3 scripts/make_helper.py +# Load environment variables if .env exists +ifneq (,$(wildcard deployment/.env)) + include deployment/.env + export +endif + +help: + @echo "PolicyEngine API v2 - Available commands:" + @echo "" + @echo "Setup (first time):" + @echo " make setup - Create .env file from template" + @echo " make init-gcp - Initialize GCP project (APIs, registry, bucket)" + @echo "" + @echo "Development:" + @echo " make dev - Start all services in development mode" + @echo " make up [service=x] - Start specific service or all services" + @echo " make down - Stop all services" + @echo " make logs [service=x] - Show logs for service" + @echo " make test - Run tests for all services" + @echo "" + @echo "Deployment:" + @echo " make deploy - Full deployment (builds, pushes, deploys project + infra)" + @echo " make terraform-init - Initialize terraform modules" + @echo " make terraform-force-init - Force reinitialize (if stuck)" + @echo " make terraform-plan - Preview changes for both modules" + @echo " make terraform-deploy-project - Deploy project configuration only" + @echo " make terraform-deploy-infra - Deploy infrastructure only" + @echo " make terraform-destroy - Destroy all terraform resources" + @echo "" + @echo "Maintenance:" + @echo " make build - Build all Docker images" + @echo " make clean - Clean up containers and volumes" + @echo " make format - Format Python code with ruff" + @echo " make check - Run code quality checks" + +# Initialize GCP (enables APIs, creates bucket, etc) +init-gcp: check-deploy-env + @bash deployment/init-gcp.sh + +# Setup for first-time users +setup: + @echo "Setting up PolicyEngine API for first time..." + @echo "Note: Using gcloud storage commands (compatible with Python 3.13+)" + @if [ ! -f deployment/.env ]; then \ + cp deployment/.env.example deployment/.env; \ + echo "✅ Created deployment/.env"; \ + echo ""; \ + echo "⚠️ IMPORTANT: Edit deployment/.env and set:"; \ + echo " - PROJECT_ID to your GCP project ID"; \ + echo " - GOOGLE_CLOUD_PROJECT to match PROJECT_ID"; \ + echo ""; \ + echo "Then run:"; \ + echo " make dev # For local development"; \ + echo " make deploy # To deploy to GCP"; \ + else \ + echo "✅ deployment/.env already exists"; \ + fi + +# Development commands +dev: + docker-compose -f deployment/docker-compose.yml up --build -# Silent commands by default, use V=1 for verbose -Q = @ -ifeq ($(V),1) - Q = +up: +ifdef service + docker-compose -f deployment/docker-compose.yml up -d $(service) +else + docker-compose -f deployment/docker-compose.yml up -d endif +down: + docker-compose -f deployment/docker-compose.yml down +logs: +ifdef service + docker-compose -f deployment/docker-compose.yml logs -f $(service) +else + docker-compose -f deployment/docker-compose.yml logs -f +endif + +# Build commands build: - $(Q)$(HELPER) section "Building all projects" - $(Q)set -e; \ - for dir in $(SUBDIRS); do \ - base=$$(basename $$dir); \ - $(HELPER) task "Building $$base" "$(MAKE) -C $$dir build"; \ - done - $(Q)$(HELPER) complete "Build completed" + docker-compose -f deployment/docker-compose.yml build --parallel -update: - $(Q)$(HELPER) section "Updating dependencies" - $(Q)set -e; \ - for dir in $(SUBDIRS); do \ - base=$$(basename $$dir); \ - $(HELPER) task "Updating $$base" "$(MAKE) -C $$dir update"; \ - done - $(Q)$(HELPER) complete "Dependencies updated" +build-prod: + docker-compose -f deployment/docker-compose.prod.yml build --parallel + +# Client generation +generate-clients: + @echo "Generating API clients..." + @./scripts/generate-clients.sh + +publish-clients: generate-clients + @echo "Publishing API clients to PyPI..." + @if [ -z "$(PYPI_TOKEN)" ]; then \ + echo "Please set PYPI_TOKEN environment variable"; \ + exit 1; \ + fi + @PYPI_TOKEN=$(PYPI_TOKEN) ./scripts/publish-clients.sh +# Testing test: - $(Q)$(HELPER) section "Running tests" - $(Q)for dir in $(SUBDIRS); do \ - base=$$(basename $$dir); \ - $(HELPER) task "Testing $$base" "$(MAKE) -C $$dir test"; \ + @echo "Running tests for all services..." + @for service in api-full api-simulation api-tagger; do \ + echo "Testing $$service..."; \ + docker-compose -f deployment/docker-compose.yml run --rm $$service sh -c "cd /app/projects/policyengine-$$service && uv run --extra test pytest" || exit 1; \ done - $(Q)$(HELPER) complete "Tests completed" -dev-api-full: - $(Q)$(HELPER) stream "Starting API (full) in dev mode" "cd projects/policyengine-api-full && make dev" +test-service: +ifndef service + @echo "Please specify service: make test-service service=api-full" +else + docker-compose -f deployment/docker-compose.yml run --rm $(service) sh -c "cd /app/projects/policyengine-$(service) && uv run --extra test pytest" +endif -dev-api-simulation: - $(Q)$(HELPER) stream "Starting API (simulation) in dev mode" "cd projects/policyengine-api-simulation && make dev" +# Integration testing +test-integration: generate-clients + @echo "Running integration tests against local services..." + @echo "Make sure services are running with 'make up' first!" + @cd projects/policyengine-apis-integ && \ + uv sync --extra test && \ + uv run pytest tests/ -v -m "not requires_gcp" -dev-api-household: - $(Q)$(HELPER) stream "Starting API (household) in dev mode" "cd projects/policyengine-household-api && make dev" +test-integration-all: generate-clients + @echo "Running all integration tests against local services..." + @echo "Make sure services are running with 'make up' first!" + @echo "Note: Workflow tests will be skipped without GCP credentials" + @cd projects/policyengine-apis-integ && \ + uv sync --extra test && \ + uv run pytest tests/ -v -dev-api-tagger: - $(Q)$(HELPER) stream "Starting API (tagger) in dev mode" "cd projects/policyengine-tagger-api && make dev" +test-integration-with-services: + @echo "Starting services and running integration tests..." + @./scripts/test-integration-local.sh -dev: - $(Q)$(HELPER) section "Starting development servers" - $(Q)$(HELPER) stream "Starting APIs (full+simulation)" "make dev-api-full & make dev-api-simulation" - -dev-setup: - $(Q)$(HELPER) section "Setting up development environment" - $(Q)set -e; \ - for dir in $(SUBDIRS); do \ - base=$$(basename $$dir); \ - $(HELPER) task "Installing $$base dependencies" "cd $$dir && uv sync --active --extra test --extra build"; \ - done - $(Q)$(HELPER) complete "Development setup completed" - -bootstrap: - $(Q)$(HELPER) task "Bootstrapping terraform" "cd terraform/project-policyengine-api && make bootstrap" - -attach: - $(Q)$(HELPER) section "Attaching terraform state" - $(Q)$(HELPER) task "Attaching project state" "$(MAKE) -C terraform/project-policyengine-api attach" - $(Q)$(HELPER) task "Attaching infrastructure state" "$(MAKE) -C terraform/infra-policyengine-api attach" - $(Q)$(HELPER) complete "Terraform state attached" - -detach: - $(Q)$(HELPER) section "Detaching terraform state" - $(Q)$(HELPER) task "Detaching project state" "$(MAKE) -C terraform/project-policyengine-api detach" - $(Q)$(HELPER) task "Detaching infrastructure state" "$(MAKE) -C terraform/infra-policyengine-api detach" - $(Q)$(HELPER) complete "Terraform state detached" - -deploy-infra: terraform/.bootstrap_settings - $(Q)$(HELPER) section "Deploying infrastructure" - $(Q)$(HELPER) task "Publishing API (full) image" "cd projects/policyengine-api-full && make deploy" - $(Q)$(HELPER) task "Publishing API (simulation) image" "cd projects/policyengine-api-simulation && make deploy" - $(Q)$(HELPER) task "Publishing API (tagger) image" "cd projects/policyengine-api-tagger && make deploy" - $(Q)$(HELPER) task "Deploying terraform infrastructure" "cd terraform/infra-policyengine-api && make deploy" - $(Q)$(HELPER) complete "Infrastructure deployed" - -deploy-project: terraform/.bootstrap_settings - $(Q)$(HELPER) task "Deploying project configuration" "cd terraform/project-policyengine-api && make deploy" - -deploy: - $(Q)$(HELPER) section "Full deployment" - $(Q)$(MAKE) deploy-project - $(Q)$(MAKE) deploy-infra - $(Q)$(HELPER) complete "Deployment completed" - -integ-test: - $(Q)$(HELPER) stream "Running integration tests" "$(MAKE) -C projects/policyengine-apis-integ" - -docker-build: - $(Q)$(HELPER) section "Building Docker images" - $(Q)$(HELPER) stream "Building policyengine-api-full image" "docker build -f projects/policyengine-api-full/Dockerfile -t policyengine-api-full:test ." - $(Q)$(HELPER) stream "Building policyengine-api-simulation image" "docker build -f projects/policyengine-api-simulation/Dockerfile -t policyengine-api-simulation:test ." - $(Q)$(HELPER) stream "Building policyengine-api-tagger image" "docker build -f projects/policyengine-api-tagger/Dockerfile -t policyengine-api-tagger:test ." - $(Q)$(HELPER) complete "Docker images built" - -docker-test: - $(Q)$(HELPER) section "Testing Docker images" - $(Q)echo "→ Testing policyengine-api-full on port 8081..." - $(Q)docker run -d --name test-api-full \ - -v $$HOME/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro \ - -e GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json \ - -e GOOGLE_CLOUD_PROJECT=beta-api-v2 \ - -p 8081:8080 policyengine-api-full:test > /dev/null - $(Q)sleep 15 - $(Q)curl -s http://127.0.0.1:8081/docs > /dev/null 2>&1; echo "✓ policyengine-api-full responding" - $(Q)docker stop test-api-full > /dev/null && docker rm test-api-full > /dev/null - $(Q)echo "→ Testing policyengine-api-simulation on port 8082..." - $(Q)docker run -d --name test-api-sim \ - -v $$HOME/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro \ - -e GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json \ - -e GOOGLE_CLOUD_PROJECT=beta-api-v2 \ - -p 8082:8080 policyengine-api-simulation:test > /dev/null - $(Q)sleep 15 - $(Q)curl -s http://127.0.0.1:8082/docs > /dev/null 2>&1; echo "✓ policyengine-api-simulation responding" - $(Q)docker stop test-api-sim > /dev/null && docker rm test-api-sim > /dev/null - $(Q)echo "→ Testing policyengine-api-tagger on port 8083..." - $(Q)docker run -d --name test-api-tag \ - -v $$HOME/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro \ - -e GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json \ - -e GOOGLE_CLOUD_PROJECT=beta-api-v2 \ - -p 8083:8080 policyengine-api-tagger:test > /dev/null - $(Q)sleep 15 - $(Q)curl -s http://127.0.0.1:8083/docs > /dev/null 2>&1; echo "✓ policyengine-api-tagger responding" - $(Q)docker stop test-api-tag > /dev/null && docker rm test-api-tag > /dev/null - $(Q)$(HELPER) complete "Docker tests completed" - -docker-check: docker-build docker-test - $(Q)$(HELPER) complete "Docker build and test completed" - -kill-ports: - $(Q)$(HELPER) section "Killing processes on development ports" - $(Q)$(HELPER) task "Killing port 8080" "lsof -ti:8080 | xargs kill -9 2>/dev/null || true" - $(Q)$(HELPER) task "Killing port 8081" "lsof -ti:8081 | xargs kill -9 2>/dev/null || true" - $(Q)$(HELPER) task "Killing port 8082" "lsof -ti:8082 | xargs kill -9 2>/dev/null || true" - $(Q)$(HELPER) task "Killing port 8083" "lsof -ti:8083 | xargs kill -9 2>/dev/null || true" - $(Q)$(HELPER) complete "Ports cleared" - -docker-debug: - $(Q)$(HELPER) section "Docker container diagnostics" - @echo "Active containers:" - @docker ps --format "table {{.Names}}\t{{.Ports}}\t{{.Status}}" - @echo "" - @if [ -n "$$(docker ps -q -f name=test-custom)" ]; then \ - echo "test-custom container logs:"; \ - docker logs test-custom --tail 30; \ - echo ""; \ - echo "Test endpoints:"; \ - echo " curl http://localhost:8090/docs"; \ - curl -s -o /dev/null -w " Response: %{http_code}\n" http://localhost:8090/docs || true; \ - else \ - echo "No test-custom container running"; \ +# Full test suite including integration +test-all: test test-integration + @echo "✅ All tests passed!" + +# Complete test suite with services startup/shutdown +test-complete: test test-integration-with-services + @echo "✅ All tests including integration passed!" + +# Deployment +deploy: check-deploy-env build-prod push-images terraform-ensure-init terraform-deploy-all + +check-deploy-env: + @if [ ! -f "deployment/.env" ]; then \ + echo "Error: deployment/.env not found. Run 'make setup' first"; \ + exit 1; \ + fi + @if [ -z "$(PROJECT_ID)" ]; then \ + echo "Error: PROJECT_ID not set in deployment/.env"; \ + exit 1; \ fi -docker-test-custom: - $(Q)$(HELPER) section "Testing custom Docker image" - @if [ -z "$(IMAGE)" ]; then \ - echo "Error: IMAGE variable not set"; \ - echo "Usage: make docker-test-custom IMAGE= [PORT=8090]"; \ - echo "Examples:"; \ - echo " make docker-test-custom IMAGE=my-image:latest"; \ - echo " make docker-test-custom IMAGE=gcr.io/project/image:tag PORT=8091"; \ +push-images: + @echo "Pushing images to GCP..." + docker-compose -f deployment/docker-compose.prod.yml push + +# Terraform commands +terraform-backend: + @echo "Setting up Terraform backend..." + @if [ -z "$(PROJECT_ID)" ]; then \ + echo "Error: PROJECT_ID not set. Please update deployment/.env"; \ exit 1; \ fi - @# Clean up any existing container - @docker rm -f test-custom 2>/dev/null || true - @# Set default port if not provided - $(eval PORT ?= 8090) - $(Q)$(HELPER) stream "Testing $(IMAGE) on port $(PORT)" "\ - trap 'echo \"\" && echo \"→ Stopping container...\" && docker stop test-custom > /dev/null && docker rm test-custom > /dev/null && echo \"✓ Container stopped and removed\" && exit 0' INT && \ - echo '→ Pulling image...' && \ - docker pull $(IMAGE) && \ - echo '→ Starting container mapping localhost:$(PORT) -> container:8080...' && \ - docker run -d --name test-custom \ - -v $$HOME/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro \ - -e GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json \ - -e GOOGLE_CLOUD_PROJECT=beta-api-v2 \ - -p $(PORT):8080 \ - --platform linux/amd64 \ - $(IMAGE) && \ - echo '→ Container started. Access at http://localhost:$(PORT)' && \ - echo '→ Waiting for service to start...' && \ - for i in 1 2 3 4 5 6; do \ - sleep 5; \ - echo ' Checking http://localhost:$(PORT)/docs (attempt' \$$i'/6)...' && \ - if curl -s http://127.0.0.1:$(PORT)/docs > /dev/null 2>&1; then \ - echo '✓ Service responding on port $(PORT)'; \ - echo '→ Access at: http://localhost:$(PORT)/docs'; \ - echo '→ Press Ctrl+C to stop the container'; \ - echo ''; \ - docker logs -f test-custom; \ - break; \ - elif [ \$$i = 6 ]; then \ - echo '✗ Service not responding after 30s on port $(PORT). Showing logs:'; \ - echo '→ Press Ctrl+C to stop the container'; \ - docker logs -f test-custom; \ - fi; \ - done" - $(Q)$(HELPER) complete "Custom image test completed" + @echo "Creating GCS bucket for Terraform state: $(PROJECT_ID)-state" + @gcloud storage buckets create gs://$(PROJECT_ID)-state \ + --project=$(PROJECT_ID) \ + --location=$(REGION) \ + --uniform-bucket-level-access 2>/dev/null || echo "Bucket already exists" + @gcloud storage buckets update gs://$(PROJECT_ID)-state --versioning + @echo "Backend bucket ready" + +terraform-force-init: + @echo "Force reinitializing Terraform (cleaning existing state)..." + @rm -rf deployment/terraform/infra/.terraform deployment/terraform/project/.terraform + @$(MAKE) terraform-init + +terraform-init: terraform-backend + @echo "Initializing Terraform..." + @# Remove example backend files if they exist + @rm -f deployment/terraform/infra/backend.example.tf deployment/terraform/infra/backend.example.tfvars + @rm -f deployment/terraform/project/backend.example.tf deployment/terraform/project/backend.example_tf + @# Create or update backend.tf files + @echo "Configuring backend for $(PROJECT_ID)-state..." + @echo "terraform {" > deployment/terraform/infra/backend.tf.tmp + @echo " backend \"gcs\" {" >> deployment/terraform/infra/backend.tf.tmp + @echo " bucket = \"$(PROJECT_ID)-state\"" >> deployment/terraform/infra/backend.tf.tmp + @echo " prefix = \"infra\"" >> deployment/terraform/infra/backend.tf.tmp + @echo " }" >> deployment/terraform/infra/backend.tf.tmp + @echo "}" >> deployment/terraform/infra/backend.tf.tmp + @mv deployment/terraform/infra/backend.tf.tmp deployment/terraform/infra/backend.tf + @echo "terraform {" > deployment/terraform/project/backend.tf.tmp + @echo " backend \"gcs\" {" >> deployment/terraform/project/backend.tf.tmp + @echo " bucket = \"$(PROJECT_ID)-state\"" >> deployment/terraform/project/backend.tf.tmp + @echo " prefix = \"project\"" >> deployment/terraform/project/backend.tf.tmp + @echo " }" >> deployment/terraform/project/backend.tf.tmp + @echo "}" >> deployment/terraform/project/backend.tf.tmp + @mv deployment/terraform/project/backend.tf.tmp deployment/terraform/project/backend.tf + @echo "Initializing project module..." + -cd deployment/terraform/project && terraform init -reconfigure 2>/dev/null || true + @echo "Initializing infra module..." + cd deployment/terraform/infra && terraform init -reconfigure + +terraform-ensure-init: + @echo "Checking Terraform initialization..." + @# Always run init if backend.tf was recently modified or .terraform doesn't exist + @if [ ! -d "deployment/terraform/infra/.terraform" ] || \ + [ "deployment/terraform/infra/backend.tf" -nt "deployment/terraform/infra/.terraform" ] || \ + [ ! -f "deployment/terraform/infra/.terraform/terraform.tfstate" ]; then \ + echo "Running terraform init..."; \ + $(MAKE) terraform-init; \ + else \ + echo "Terraform already initialized"; \ + fi + +terraform-plan: terraform-ensure-init + @echo "Planning Terraform changes..." + @if [ -z "$(TF_VAR_org_id)" ] || [ "$(TF_VAR_org_id)" = "your-org-id" ]; then \ + echo "\n=== Skipping PROJECT module (using existing project) ==="; \ + else \ + echo "\n=== Planning PROJECT module ==="; \ + cd deployment/terraform/project && terraform plan; \ + fi + @echo "\n=== Planning INFRA module ===" + @# Auto-populate all required variables + @US_VERSION=$$(grep -A1 'name = "policyengine-us"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') && \ + UK_VERSION=$$(grep -A1 'name = "policyengine-uk"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') && \ + COMMIT_URL="https://github.com/PolicyEngine/policyengine-api-v2/commit/$$(git rev-parse HEAD)" && \ + echo "project_id = \"$${TF_VAR_project_id}\"" > deployment/terraform/infra/auto.tfvars && \ + echo "commit_url = \"$$COMMIT_URL\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "policyengine-us-package-version = \"$$US_VERSION\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "policyengine-uk-package-version = \"$$UK_VERSION\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "is_prod = $${TF_VAR_is_prod:-false}" >> deployment/terraform/infra/auto.tfvars && \ + echo "full_container_tag = \"$${TF_VAR_full_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "simulation_container_tag = \"$${TF_VAR_simulation_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "tagger_container_tag = \"$${TF_VAR_tagger_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "region = \"$${TF_VAR_region:-us-central1}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "stage = \"$${TF_VAR_stage:-dev}\"" >> deployment/terraform/infra/auto.tfvars && \ + cd deployment/terraform/infra && terraform plan -var-file=auto.tfvars + +terraform-deploy-project: terraform-ensure-init + @echo "Deploying GCP project configuration..." + @echo "Note: This creates a NEW GCP project. Skip if using existing project." + @if [ -z "$(TF_VAR_org_id)" ] || [ "$(TF_VAR_org_id)" = "your-org-id" ]; then \ + echo "⚠️ Skipping project creation - TF_VAR_org_id not set"; \ + echo " Using existing project: $(PROJECT_ID)"; \ + else \ + cd deployment/terraform/project && terraform apply -auto-approve; \ + fi + +terraform-deploy-infra: terraform-ensure-init + @echo "Deploying infrastructure (Cloud Run, etc)..." + @# Auto-populate all required variables + @US_VERSION=$$(grep -A1 'name = "policyengine-us"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') && \ + UK_VERSION=$$(grep -A1 'name = "policyengine-uk"' projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') && \ + COMMIT_URL="https://github.com/PolicyEngine/policyengine-api-v2/commit/$$(git rev-parse HEAD)" && \ + echo "project_id = \"$${TF_VAR_project_id}\"" > deployment/terraform/infra/auto.tfvars && \ + echo "commit_url = \"$$COMMIT_URL\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "policyengine-us-package-version = \"$$US_VERSION\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "policyengine-uk-package-version = \"$$UK_VERSION\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "is_prod = $${TF_VAR_is_prod:-false}" >> deployment/terraform/infra/auto.tfvars && \ + echo "full_container_tag = \"$${TF_VAR_full_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "simulation_container_tag = \"$${TF_VAR_simulation_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "tagger_container_tag = \"$${TF_VAR_tagger_container_tag:-latest}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "region = \"$${TF_VAR_region:-us-central1}\"" >> deployment/terraform/infra/auto.tfvars && \ + echo "stage = \"$${TF_VAR_stage:-dev}\"" >> deployment/terraform/infra/auto.tfvars && \ + cd deployment/terraform/infra && terraform apply -auto-approve -var-file=auto.tfvars + +terraform-deploy-all: terraform-ensure-init + @echo "Starting full deployment..." + @# Try project deployment but don't fail if skipped + @$(MAKE) terraform-deploy-project || true + @# Always deploy infrastructure + @$(MAKE) terraform-deploy-infra + @echo "✅ Deployment completed successfully!" + +terraform-deploy: terraform-deploy-all # Alias for backward compatibility + +terraform-import: + @echo "Importing existing resources into terraform state..." + @cd deployment/terraform && ./import-existing.sh + +terraform-handle-workflows: + @echo "Checking and handling existing workflows..." + @cd deployment/terraform && ./handle-existing-workflows.sh $(PROJECT_ID) $(TF_VAR_region) + +terraform-destroy: + @echo "⚠️ WARNING: This will destroy all terraform-managed resources!" + @echo "Press Ctrl+C to cancel, or Enter to continue..." + @read confirm + @echo "Destroying infrastructure first..." + cd deployment/terraform/infra && terraform destroy -auto-approve + @echo "Destroying project configuration..." + cd deployment/terraform/project && terraform destroy -auto-approve + @echo "✅ All terraform resources destroyed" + +# Update dependencies +update: + @echo "Updating dependencies for all packages..." + @for pyproject in libs/*/pyproject.toml projects/*/pyproject.toml; do \ + if [ -f "$$pyproject" ]; then \ + dir=$$(dirname "$$pyproject"); \ + echo "Updating $$dir..."; \ + (cd "$$dir" && uv lock --upgrade); \ + fi \ + done + @echo "✅ All dependencies updated" + +# Code quality +format: + @echo "Formatting code with ruff..." + @for dir in projects/*/src libs/*/src; do \ + if [ -d "$$dir" ]; then \ + echo "Formatting $$dir..."; \ + uv run ruff format $$dir; \ + fi \ + done + +check: + @echo "Running code quality checks..." + @for dir in projects/*/src libs/*/src; do \ + if [ -d "$$dir" ]; then \ + echo "Checking $$dir..."; \ + uv run ruff check $$dir; \ + uv run pyright $$dir; \ + fi \ + done + +# Integration tests +integ-test: + cd projects/policyengine-apis-integ && uv run pytest + +# Cleanup +clean: + find . -type d -name "__pycache__" -exec rm -r {} +; \ + find . -name ".coverage" -exec rm -r {} +; \ + find . -name "artifacts" -exec rm -r {} +; \ + find . -name ".pytest_cache" -exec rm -r {} +; \ + find . -name ".venv" -exec rm -r {} +; + + docker-compose -f deployment/docker-compose.yml down -v + docker system prune -f + +# Local development helpers +shell: +ifndef service + @echo "Please specify service: make shell service=api-full" +else + docker-compose -f deployment/docker-compose.yml exec $(service) /bin/bash +endif + +ps: + docker-compose -f deployment/docker-compose.yml ps + +# Production helpers +prod-build: + docker-compose -f deployment/docker-compose.prod.yml build + +prod-push: + docker-compose -f deployment/docker-compose.prod.yml push + +# Quick commands for specific services +dev-full: + docker-compose -f deployment/docker-compose.yml up api-full + +dev-sim: + docker-compose -f deployment/docker-compose.yml up api-simulation + +dev-tagger: + docker-compose -f deployment/docker-compose.yml up api-tagger diff --git a/Makefile.deploy b/Makefile.deploy deleted file mode 100644 index b626baef..00000000 --- a/Makefile.deploy +++ /dev/null @@ -1,21 +0,0 @@ -publish-full-api-docker: - cd projects/policyengine-api-full && make -f Makefile.deploy deploy TAG=${TAG} PROJECT_ID=${PROJECT_ID} - -publish-simulation-api-docker: - cd projects/policyengine-api-simulation && make -f Makefile.deploy deploy TAG=${TAG} PROJECT_ID=${PROJECT_ID} - -publish-tagger-api-docker: - cd projects/policyengine-api-tagger && make -f Makefile.deploy deploy TAG=${TAG} PROJECT_ID=${PROJECT_ID} - -deploy-project: - cd terraform/project-policyengine-api && make -f Makefile.deploy deploy - -deploy-infra: - cd terraform/infra-policyengine-api && make -f Makefile.deploy deploy - -integ-test: - # generate the service client - cd projects/policyengine-api-full && make build - cd projects/policyengine-api-simulation && make build - # run the integration test using the client. - cd projects/policyengine-apis-integ && make FULL_API_URL='$(FULL_API_URL)' SIMULATION_API_URL='$(SIMULATION_API_URL)' FULL_API_ACCESS_TOKEN='$(FULL_API_ACCESS_TOKEN)' SIMULATION_API_ACCESS_TOKEN='$(SIMULATION_API_ACCESS_TOKEN)' diff --git a/README.md b/README.md index 967b6f74..da00d0aa 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,176 @@ -Monorepo containing all the libraries, applications, terraform and github actions required to build/test/deploy/release the PolicyEngine api V2. - -# Local Development Quick Start -* [install poetry](https://python-poetry.org/docs/#installation) -* ``make build`` - install and pytest all libraries and projects. - -# Cloud Development Quick Start -__NOTE: MOST development should be possible locally. Deployment is slow and hard to debug. Change with caution__ - -* One time setup - this will create a new project in your GCP account you can deploy the api to. - * Create a gcp account _with organization_ - * authenticate with gcloud as a user with permission to create projects. - * ``gcloud auth application-default login`` - * Have your organization ID and billing account number handy. - * ``cd terraform/infra-policyengine-api && make bootstrap`` - * You should now have a terraform/.bootstrap_settings folder containing your project settings. -* build the api docker image - * ``cd projects/policyengine-api-full && make deploy`` - * There should now be a new hash under the tag "desktop" in the project artifact repository. -* deploy to the cloud - * ``cd terraform/project-policyengine-api-full && make deploy`` - * The cloudrun service should now be running using the latest image version of the tag "desksop" from your project artifact respository - -# Github Deploy to Cloud Quick Start - -__checkout a clean version of the repository__ you cannot bootstrap more than one project -in a workspace at a time. - -* bootstrap the beta project - * have your github repo owner id and repo (i.e. org/repo) ready - * have your GCP organization id and billing account number ready - * log into your gcp account via gcloud as a user able to create projects. - * ``cd terraform/project-poicyengine-api && make bootstrap_beta`` -* WAIT FOR AT LEAST AN HOUR (permissions configuration sometimes takes up to an hour for the github federation.) You may get errors about lack of permission (or possibly resource) for thinkgs like the deployment state bucket. -* configure github - * create a new environment in your github repo settings called "beta" and, using the ouput of the bootstrap, configure the following values - * REGION (generally us-central1) - * PROJECT_ID (in the output of the bootstrap target) - * _GITHUB_IDENTITY_POOL_PROVIDER_NAME (in the output of the bootstrap build target) - * ORG_ID - * BILLING_ACCOUNT +# PolicyEngine API v2 + +Monorepo for PolicyEngine's API infrastructure, containing all services, libraries, and deployment configuration. + +## Quick start + +### Prerequisites + +- Docker and Docker Compose +- Python 3.13+ +- [uv](https://docs.astral.sh/uv/) package manager +- gcloud CLI (for deployment) +- Terraform 1.5+ (for deployment) + +### Local development + +Start all services: +```bash +make up # Start services on ports 8081-8083 +make logs # View logs +make down # Stop services +``` + +Run the test suite: +```bash +make test # Unit tests only +make test-integration-with-services # Full integration tests (manages services automatically) +make test-complete # Everything: unit + integration tests +``` + +## Architecture + +The repository contains three main API services: + +- **api-full** (port 8081): Main PolicyEngine API with household calculations +- **api-simulation** (port 8082): Economic simulation engine +- **api-tagger** (port 8083): Cloud Run revision management + +Each service generates OpenAPI specs and Python client libraries for integration testing. + +## Development workflow + +### Making changes + +1. Edit code locally - services hot-reload automatically when running via `make up` +2. Run tests: `make test-complete` +3. Commit changes to a feature branch +4. Open a PR - GitHub Actions will run tests automatically + +### Testing + +Unit tests run in isolated containers: +```bash +make test # All services +make test-service service=api-full # Single service +``` + +Integration tests use generated client libraries: +```bash +make generate-clients # Generate OpenAPI clients (done automatically by test commands) +make test-integration # Run integration tests (requires services running) +``` + +### Project structure + +``` +/ +├── projects/ # Service applications +│ ├── policyengine-api-full/ +│ ├── policyengine-api-simulation/ +│ ├── policyengine-api-tagger/ +│ └── policyengine-apis-integ/ # Integration tests +├── libs/ # Shared libraries +│ └── policyengine-fastapi/ # Common FastAPI utilities +├── deployment/ # Deployment configuration +│ ├── docker-compose.yml # Local development +│ ├── docker-compose.prod.yml # Production builds +│ └── terraform/ # Infrastructure as code +├── scripts/ # Utility scripts +└── .github/workflows/ # CI/CD pipelines +``` + +## Deployment + +### Setting up a new GCP project + +**Important**: Most development should be done locally. Cloud deployment is slow and harder to debug. + +1. Configure environment: +```bash +cp deployment/.env.example deployment/.env +# Edit deployment/.env with your GCP project details +``` + +2. Deploy infrastructure: +```bash +make deploy # Builds images, pushes to registry, runs terraform +``` + +For existing GCP projects with resources: +```bash +make terraform-import # Import existing resources +./deployment/terraform/handle-existing-workflows.sh $PROJECT_ID --delete # Handle workflows +``` + +See [deployment guide](deployment/DEPLOYMENT_GUIDE.md) for detailed instructions. + +### GitHub Actions deployment + +The repository includes automated deployment pipelines: + +1. **Pull requests**: Runs tests and builds +2. **Merge to main**: + - Deploys to beta environment + - Runs integration tests + - Deploys to production + - Publishes API client packages to PyPI + +Configure GitHub environments with these variables: +- `PROJECT_ID`: GCP project ID +- `REGION`: GCP region (usually us-central1) +- `_GITHUB_IDENTITY_POOL_PROVIDER_NAME`: Workload identity provider + +### Important notes from experience + +- **Wait after bootstrap**: GCP permission propagation can take up to an hour +- **Workflows can't be imported**: Use the provided script to handle existing workflows +- **Always test locally first**: Cloud debugging is painful +- **Check terraform state**: If deployments fail, check if resources already exist + +## Commands reference + +### Development +- `make up` - Start services locally +- `make down` - Stop services +- `make logs` - View service logs +- `make build` - Build Docker images + +### Testing +- `make test` - Run unit tests +- `make test-integration` - Run integration tests +- `make test-complete` - Run all tests with service management +- `make generate-clients` - Generate API client libraries + +### Deployment +- `make deploy` - Full deployment to GCP +- `make terraform-plan` - Preview infrastructure changes +- `make terraform-import` - Import existing resources +- `make terraform-destroy` - Remove all infrastructure +- `make publish-clients` - Publish API clients to PyPI (requires PYPI_TOKEN) + +## Troubleshooting + +### Services won't start +- Check Docker is running +- Ensure ports 8081-8083 are free +- Run `make build` to rebuild images + +### Integration tests fail +- Regenerate clients: `make generate-clients` +- Check services are healthy: `make logs` +- Verify port configuration matches docker-compose.yml + +### Deployment issues +- Check deployment/.env configuration +- Verify GCP authentication: `gcloud auth list` +- For "already exists" errors: `make terraform-import` +- For workflow errors: `./deployment/terraform/handle-existing-workflows.sh` + +## Contributing + +1. Create a feature branch +2. Make changes and test locally +3. Ensure `make test-complete` passes +4. Open a PR with a clear description +5. Wait for CI checks to pass \ No newline at end of file diff --git a/cloudbuild.yaml b/cloudbuild.yaml deleted file mode 100644 index c16fd47e..00000000 --- a/cloudbuild.yaml +++ /dev/null @@ -1,9 +0,0 @@ -steps: - - name: 'gcr.io/cloud-builders/docker' - args: ['build', '-t', '${_IMAGE_TAG}', '--build-arg', 'SERVICE_NAME=${_SERVICE_NAME}', '--build-arg', 'MODULE_NAME=${_MODULE_NAME}', '--build-arg', 'WORKER_COUNT=${_WORKER_COUNT}', '.'] - - - name: 'gcr.io/cloud-builders/docker' - args: ['push', '${_IMAGE_TAG}'] - -images: - - '${_IMAGE_TAG}' diff --git a/common.mk b/common.mk deleted file mode 100644 index daa22f91..00000000 --- a/common.mk +++ /dev/null @@ -1,58 +0,0 @@ --include ../../terraform/.bootstrap_settings/project.env - - -# Helper for pretty output -HELPER := python ../../scripts/ensure_rich.py && python ../../scripts/make_helper.py - -# Silent commands by default, use V=1 for verbose -Q = @ -ifeq ($(V),1) - Q = -endif - -build: remove_artifacts install checkformat pyright generate test - -remove_artifacts: - $(Q)$(HELPER) subtask "Removing artifacts" "rm -rf artifacts" - -install: - $(Q)$(HELPER) subtask "Installing dependencies" "uv sync --active --extra test --extra build" - -checkformat: - $(Q)dirs=""; \ - [ -d "src" ] && dirs="$$dirs src"; \ - [ -d "tests" ] && dirs="$$dirs tests"; \ - if [ -n "$$dirs" ]; then \ - $(HELPER) subtask "Checking code format" "black --check $$dirs"; \ - else \ - $(HELPER) subtask "Checking code format" "echo 'No source directories found'"; \ - fi - -format: - $(Q)dirs=""; \ - [ -d "src" ] && dirs="$$dirs src"; \ - [ -d "tests" ] && dirs="$$dirs tests"; \ - if [ -n "$$dirs" ]; then \ - $(HELPER) subtask "Formatting code" "black $$dirs"; \ - else \ - $(HELPER) subtask "Formatting code" "echo 'No source directories found'"; \ - fi - -# Default targets that can be overridden - defined only if not already defined -ifndef HAS_CUSTOM_PYRIGHT -pyright: - $(Q)$(HELPER) subtask "Type checking" "pyright" -endif - -ifndef HAS_CUSTOM_TEST -test: - $(Q)$(HELPER) subtask "Running tests" "pytest" -endif - -ifndef HAS_CUSTOM_GENERATE -generate: - $(Q)$(HELPER) subtask "Code generation" "echo 'No generation target defined'" -endif - -update: - $(Q)$(HELPER) subtask "Updating lockfile" "uv lock --upgrade" diff --git a/deployment/.env.example b/deployment/.env.example new file mode 100644 index 00000000..17743f09 --- /dev/null +++ b/deployment/.env.example @@ -0,0 +1,38 @@ +############################################################################### +# OPTION 1: Using EXISTING GCP project (recommended for most users) +############################################################################### +# Set your existing project ID here: +PROJECT_ID=your-existing-project-id +GOOGLE_CLOUD_PROJECT=${PROJECT_ID} # Should match PROJECT_ID +REGION=us-central1 +REPO=api-v2 + +############################################################################### +# OPTION 2: Create NEW GCP project via terraform (advanced) +############################################################################### +# Uncomment and fill these ONLY if you want terraform to create a new project: +# TF_VAR_org_id=your-org-id # Get from: gcloud organizations list +# TF_VAR_billing_account=your-billing-account # Get from: gcloud billing accounts list +# TF_VAR_project_name=policyengine-api # Base name for project +# TF_VAR_github_repo_owner_id=your-github-org # GitHub organization +# TF_VAR_github_repo=policyengine-api-v2 # GitHub repo name +# TF_VAR_github_repo_ref=main # Branch to deploy from + +############################################################################### +# Infrastructure configuration (required for all) +############################################################################### +# Terraform Variables (auto-populated from above) +TF_VAR_project_id=${PROJECT_ID} +TF_VAR_region=${REGION} +TF_VAR_stage=dev # dev, staging, or prod +TF_VAR_is_prod=false # true for production +TF_VAR_full_container_tag=latest +TF_VAR_simulation_container_tag=latest +TF_VAR_tagger_container_tag=latest + +# Build configuration +TAG=latest +ENVIRONMENT=desktop # desktop or production + +# Optional: Slack notifications +# TF_VAR_slack_notification_channel_name=your-slack-channel \ No newline at end of file diff --git a/deployment/DEPLOYMENT_GUIDE.md b/deployment/DEPLOYMENT_GUIDE.md new file mode 100644 index 00000000..71b58f03 --- /dev/null +++ b/deployment/DEPLOYMENT_GUIDE.md @@ -0,0 +1,57 @@ +# Deployment guide + +## Prerequisites + +- GCP project with billing enabled +- `gcloud` CLI installed and authenticated +- Docker installed +- Terraform 1.5+ installed + +## Setup + +1. Copy and configure environment: +```bash +cp deployment/.env.example deployment/.env +# Edit deployment/.env with your project details +``` + +2. For existing GCP projects with resources: +```bash +# If you get "already exists" errors, run: +make terraform-import + +# For workflow errors specifically (workflows can't be imported): +./deployment/terraform/handle-existing-workflows.sh $PROJECT_ID +# To auto-delete existing workflows, add --delete flag: +# ./deployment/terraform/handle-existing-workflows.sh $PROJECT_ID us-central1 --delete +``` + +3. Deploy: +```bash +make deploy +``` + +## How it works + +- **Terraform state**: Stored in GCS bucket `{PROJECT_ID}-state` +- **Auto-populated variables**: Commit URL and package versions are extracted automatically +- **Shared state**: Works across multiple machines via GCS backend + +## Troubleshooting + +### Resources already exist errors + +If you see errors about resources already existing: + +1. Run `make terraform-import` to import existing resources +2. Then run `make deploy` again + +### Starting fresh + +To destroy all terraform-managed resources: + +```bash +make terraform-destroy +``` + +Then you can deploy fresh with `make deploy`. \ No newline at end of file diff --git a/deployment/README.md b/deployment/README.md new file mode 100644 index 00000000..81ca47b2 --- /dev/null +++ b/deployment/README.md @@ -0,0 +1,24 @@ +# Deployment configuration + +This directory contains all deployment-related files: + +- `docker-compose.yml` - Local development environment +- `docker-compose.prod.yml` - Production build configuration +- `.env.example` - Example environment variables +- `cloudbuild.yaml` - GCP Cloud Build configuration + +## Quick start + +```bash +# Copy environment variables +cp deployment/.env.example deployment/.env + +# Start local development +make dev + +# Build production images +make build-prod + +# Deploy to GCP +make deploy +``` \ No newline at end of file diff --git a/deployment/cloudbuild.yaml b/deployment/cloudbuild.yaml new file mode 100644 index 00000000..f7447615 --- /dev/null +++ b/deployment/cloudbuild.yaml @@ -0,0 +1,11 @@ +# Cloud Build configuration for building Docker images +# Used when deploying via GCP Cloud Build instead of local docker-compose +steps: + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', '${_IMAGE_TAG}', '-f', 'projects/${_SERVICE_NAME}/Dockerfile', '.'] + + - name: 'gcr.io/cloud-builders/docker' + args: ['push', '${_IMAGE_TAG}'] + +images: + - '${_IMAGE_TAG}' \ No newline at end of file diff --git a/deployment/docker-compose.prod.yml b/deployment/docker-compose.prod.yml new file mode 100644 index 00000000..5bc3ce33 --- /dev/null +++ b/deployment/docker-compose.prod.yml @@ -0,0 +1,24 @@ +services: + api-full: + image: ${REGION:-us-central1}-docker.pkg.dev/${PROJECT_ID}/${REPO:-api-v2}/policyengine-api-full:${TAG:-latest} + build: + context: .. + dockerfile: projects/policyengine-api-full/Dockerfile + platforms: + - linux/amd64 + + api-simulation: + image: ${REGION:-us-central1}-docker.pkg.dev/${PROJECT_ID}/${REPO:-api-v2}/policyengine-api-simulation:${TAG:-latest} + build: + context: .. + dockerfile: projects/policyengine-api-simulation/Dockerfile + platforms: + - linux/amd64 + + api-tagger: + image: ${REGION:-us-central1}-docker.pkg.dev/${PROJECT_ID}/${REPO:-api-v2}/policyengine-api-tagger:${TAG:-latest} + build: + context: .. + dockerfile: projects/policyengine-api-tagger/Dockerfile + platforms: + - linux/amd64 diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml new file mode 100644 index 00000000..e757e59a --- /dev/null +++ b/deployment/docker-compose.yml @@ -0,0 +1,58 @@ +services: + api-full: + build: + context: .. + dockerfile: projects/policyengine-api-full/Dockerfile + environment: + - ENVIRONMENT=desktop + - GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json + - GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT:-beta-api-v2} + volumes: + - ~/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro + - ../projects/policyengine-api-full/src:/app/projects/policyengine-api-full/src + - ../libs:/app/libs + ports: + - "8081:8080" + command: sh -c "cd src && uv run uvicorn policyengine_api_full.main:app --reload --host 0.0.0.0 --port 8080" + networks: + - policyengine + + api-simulation: + build: + context: .. + dockerfile: projects/policyengine-api-simulation/Dockerfile + environment: + - ENVIRONMENT=desktop + - GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json + - GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT:-beta-api-v2} + volumes: + - ~/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro + - ../projects/policyengine-api-simulation/src:/app/projects/policyengine-api-simulation/src + - ../libs:/app/libs + ports: + - "8082:8080" + command: sh -c "cd src && uv run uvicorn policyengine_api_simulation.main:app --reload --host 0.0.0.0 --port 8080" + networks: + - policyengine + + api-tagger: + build: + context: .. + dockerfile: projects/policyengine-api-tagger/Dockerfile + environment: + - ENVIRONMENT=desktop + - GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json + - GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT:-beta-api-v2} + volumes: + - ~/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro + - ../projects/policyengine-api-tagger/src:/app/projects/policyengine-api-tagger/src + - ../libs:/app/libs + ports: + - "8083:8080" + command: sh -c "cd src && uv run uvicorn policyengine_api_tagger.main:app --reload --host 0.0.0.0 --port 8080" + networks: + - policyengine + +networks: + policyengine: + driver: bridge \ No newline at end of file diff --git a/deployment/init-gcp.sh b/deployment/init-gcp.sh new file mode 100755 index 00000000..41826379 --- /dev/null +++ b/deployment/init-gcp.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# Quick GCP initialization script + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Source .env file +if [ ! -f "deployment/.env" ]; then + echo -e "${RED}Error: deployment/.env not found${NC}" + echo "Run 'make setup' first" + exit 1 +fi + +source deployment/.env + +echo -e "${GREEN}Initializing GCP for PolicyEngine API${NC}" +echo "Project ID: $PROJECT_ID" +echo "Region: $REGION" + +# Check if logged in +echo -e "\n${YELLOW}Checking GCP authentication...${NC}" +if ! gcloud auth list --filter=status:ACTIVE --format="value(account)" | grep -q .; then + echo "Not logged in to GCP. Running 'gcloud auth login'..." + gcloud auth login +fi + +# Set project +echo -e "\n${YELLOW}Setting GCP project...${NC}" +gcloud config set project $PROJECT_ID + +# Enable required APIs +echo -e "\n${YELLOW}Enabling required GCP APIs...${NC}" +gcloud services enable \ + artifactregistry.googleapis.com \ + cloudbuild.googleapis.com \ + compute.googleapis.com \ + run.googleapis.com \ + cloudresourcemanager.googleapis.com \ + serviceusage.googleapis.com \ + workflows.googleapis.com \ + cloudtrace.googleapis.com \ + monitoring.googleapis.com \ + secretmanager.googleapis.com \ + --project=$PROJECT_ID + +# Create Artifact Registry if it doesn't exist +echo -e "\n${YELLOW}Creating Artifact Registry repository...${NC}" +gcloud artifacts repositories create $REPO \ + --repository-format=docker \ + --location=$REGION \ + --description="PolicyEngine API Docker images" \ + --project=$PROJECT_ID 2>/dev/null || echo "Repository already exists" + +# Configure Docker +echo -e "\n${YELLOW}Configuring Docker authentication...${NC}" +gcloud auth configure-docker $REGION-docker.pkg.dev + +# Create terraform state bucket +echo -e "\n${YELLOW}Creating Terraform state bucket...${NC}" +gcloud storage buckets create gs://$PROJECT_ID-state \ + --project=$PROJECT_ID \ + --location=$REGION \ + --uniform-bucket-level-access 2>/dev/null || echo "Bucket already exists" +gcloud storage buckets update gs://$PROJECT_ID-state --versioning + +echo -e "\n${GREEN}✅ GCP initialization complete!${NC}" +echo -e "\nNext steps:" +echo " 1. Run 'make build-prod' to build Docker images" +echo " 2. Run 'make deploy' to deploy to GCP" \ No newline at end of file diff --git a/terraform/.gitignore b/deployment/terraform/.gitignore similarity index 100% rename from terraform/.gitignore rename to deployment/terraform/.gitignore diff --git a/deployment/terraform/NEW_PROJECT_SETUP.md b/deployment/terraform/NEW_PROJECT_SETUP.md new file mode 100644 index 00000000..b657c203 --- /dev/null +++ b/deployment/terraform/NEW_PROJECT_SETUP.md @@ -0,0 +1,241 @@ +# Setting up terraform for a new GCP project + +This guide walks through deploying PolicyEngine API to a new GCP project. + +## Prerequisites + +1. **GCP account** with billing enabled +2. **gcloud CLI** installed and authenticated +3. **Terraform** installed (v1.0+) +4. **Docker** installed for building images +5. **Appropriate IAM permissions** to create projects and resources + +## Step 1: Create and configure GCP project + +### Option A: Create new project via terraform +```bash +# Configure project variables +cd deployment/terraform/project +cp apply.example.tfvars terraform.tfvars + +# Edit terraform.tfvars with your details: +# - org_id: Your GCP organization ID +# - billing_account: Your billing account ID +# - stage: Environment name (e.g., "prod", "staging", "dev") +# - project_name: Base name for the project + +# Initialize and apply +terraform init +terraform apply +``` + +### Option B: Use existing project +Skip the project creation and note your existing project ID. + +## Step 2: Set up terraform state backend + +```bash +# Create a GCS bucket for terraform state +export PROJECT_ID="your-project-id" +export BUCKET_NAME="${PROJECT_ID}-state" +export REGION="us-central1" + +# Using gcloud storage (works with Python 3.13+) +gcloud storage buckets create gs://${BUCKET_NAME} \ + --project=${PROJECT_ID} \ + --location=${REGION} \ + --uniform-bucket-level-access + +gcloud storage buckets update gs://${BUCKET_NAME} --versioning + +# Configure backend for both modules +cd deployment/terraform/project +cp backend.example.tf backend.tf +# Edit backend.tf and set bucket = "your-project-id-state" + +cd ../infra +cp backend.example.tfvars backend.tfvars +# Edit backend.tfvars and set bucket = "your-project-id-state" +``` + +## Step 3: Enable required APIs + +```bash +gcloud services enable \ + artifactregistry.googleapis.com \ + cloudbuild.googleapis.com \ + compute.googleapis.com \ + run.googleapis.com \ + cloudresourcemanager.googleapis.com \ + serviceusage.googleapis.com \ + workflows.googleapis.com \ + cloudtrace.googleapis.com \ + monitoring.googleapis.com \ + secretmanager.googleapis.com \ + --project=${PROJECT_ID} +``` + +## Step 4: Create Artifact Registry repository + +```bash +# Create Docker repository for container images +gcloud artifacts repositories create api-v2 \ + --repository-format=docker \ + --location=us-central1 \ + --description="PolicyEngine API Docker images" \ + --project=${PROJECT_ID} + +# Configure Docker authentication +gcloud auth configure-docker us-central1-docker.pkg.dev +``` + +## Step 5: Build and push Docker images + +```bash +# Set environment variables +export PROJECT_ID="your-project-id" +export REGION="us-central1" +export REPO="api-v2" +export TAG="initial" + +# Build and push images +cd /path/to/policyengine-api-v2 +make build-prod +make push-images +``` + +## Step 6: Deploy infrastructure + +```bash +cd deployment/terraform/infra + +# Configure variables +cp apply.example.tfvars terraform.tfvars +# Edit terraform.tfvars: +# - project_id: Your GCP project ID +# - region: Target region (e.g., "us-central1") +# - stage: Environment name +# - is_prod: true for production, false otherwise +# - container tags for each service + +# Initialize and deploy +terraform init -backend-config="bucket=${PROJECT_ID}-state" +terraform plan +terraform apply +``` + +## Step 7: Configure secrets (if needed) + +```bash +# Add any required secrets to Secret Manager +gcloud secrets create hugging-face-token \ + --data-file=path/to/token.txt \ + --project=${PROJECT_ID} + +# Grant service account access +gcloud secrets add-iam-policy-binding hugging-face-token \ + --member="serviceAccount:simulation-workflows-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/secretmanager.secretAccessor" \ + --project=${PROJECT_ID} +``` + +## Step 8: Verify deployment + +```bash +# List deployed services +gcloud run services list --project=${PROJECT_ID} + +# Get service URLs +gcloud run services describe full-api \ + --region=${REGION} \ + --project=${PROJECT_ID} \ + --format="value(status.url)" + +# Test endpoints +curl $(gcloud run services describe full-api \ + --region=${REGION} \ + --project=${PROJECT_ID} \ + --format="value(status.url)")/ping/alive +``` + +## Environment-specific configurations + +### Development +- Set `is_prod = false` in terraform.tfvars +- Minimum instances set to 0 (scale to zero) +- Relaxed concurrency limits + +### Production +- Set `is_prod = true` in terraform.tfvars +- Minimum instances kept warm (min_instance_count = 1) +- Configure monitoring and alerting +- Set up custom domain (optional) + +## Updating deployments + +For subsequent deployments to the same project: + +```bash +# Update code and rebuild images +export TAG="v1.2.3" # or git commit SHA +make build-prod +make push-images + +# Update terraform with new image tags +cd deployment/terraform/infra +# Edit terraform.tfvars with new container tags +terraform apply +``` + +## Cleanup + +To tear down all resources: + +```bash +cd deployment/terraform/infra +terraform destroy + +cd ../project +terraform destroy # Only if you created the project via terraform +``` + +## Troubleshooting + +### Authentication issues +```bash +gcloud auth application-default login +gcloud config set project ${PROJECT_ID} +``` + +### Terraform state issues +```bash +# Force unlock if state is locked +terraform force-unlock + +# Refresh state +terraform refresh +``` + +### Service deployment issues +```bash +# Check Cloud Run logs +gcloud run services logs read full-api \ + --region=${REGION} \ + --project=${PROJECT_ID} + +# Check service details +gcloud run services describe full-api \ + --region=${REGION} \ + --project=${PROJECT_ID} +``` + +## Required IAM roles + +Ensure your account has these roles: +- `roles/resourcemanager.projectCreator` (if creating new project) +- `roles/billing.user` +- `roles/iam.serviceAccountAdmin` +- `roles/run.admin` +- `roles/artifactregistry.admin` +- `roles/workflows.admin` +- `roles/storage.admin` (for terraform state) \ No newline at end of file diff --git a/deployment/terraform/README.md b/deployment/terraform/README.md new file mode 100644 index 00000000..374fb19d --- /dev/null +++ b/deployment/terraform/README.md @@ -0,0 +1,35 @@ +# Terraform infrastructure + +Two terraform modules for deploying PolicyEngine API: + +## Modules + +- `project/` - GCP project setup and configuration +- `infra/` - Cloud Run services and infrastructure + +## Usage + +```bash +# Initialize terraform +make terraform-init + +# Plan changes +make terraform-plan + +# Deploy infrastructure +make terraform-deploy +``` + +## Configuration + +1. Copy example files: +```bash +cp project/apply.example.tfvars project/terraform.tfvars +cp infra/apply.example.tfvars infra/terraform.tfvars +``` + +2. Update the `.tfvars` files with your GCP project details + +3. Backend storage is automatically configured when you run `make terraform-init` + - Creates GCS bucket: `{PROJECT_ID}-state` + - Generates `backend.tf` files with correct configuration \ No newline at end of file diff --git a/deployment/terraform/handle-existing-workflows.sh b/deployment/terraform/handle-existing-workflows.sh new file mode 100755 index 00000000..f967a655 --- /dev/null +++ b/deployment/terraform/handle-existing-workflows.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Script to handle existing workflows before terraform deployment + +set -e + +# Get project ID from command line or environment +PROJECT_ID="${1:-${TF_VAR_project_id}}" +REGION="${2:-${TF_VAR_region:-us-central1}}" + +if [ -z "$PROJECT_ID" ]; then + echo "Usage: $0 [region]" + echo "Or set TF_VAR_project_id environment variable" + exit 1 +fi + +echo "Checking for existing workflows in project: $PROJECT_ID, region: $REGION" + +# Check if workflows exist +EXISTING_WORKFLOWS=$(gcloud workflows list --location="$REGION" --project="$PROJECT_ID" --format="value(name)" 2>/dev/null || true) + +# Check for our specific workflows +for workflow in "simulation-workflow" "wait-for-country-packages"; do + if echo "$EXISTING_WORKFLOWS" | grep -q "$workflow"; then + echo "Found existing workflow: $workflow" + echo "Options:" + echo " 1. Delete the workflow manually:" + echo " gcloud workflows delete $workflow --location=$REGION --project=$PROJECT_ID" + echo "" + echo " 2. Or use terraform import (but this may not work with all configurations):" + echo " cd deployment/terraform/infra" + echo " terraform import google_workflows_workflow.$(echo $workflow | tr '-' '_') projects/$PROJECT_ID/locations/$REGION/workflows/$workflow" + echo "" + FOUND_EXISTING=true + fi +done + +if [ "$FOUND_EXISTING" = true ]; then + echo "" + echo "⚠️ Existing workflows found. You have two options:" + echo "" + echo "Option A: Delete existing workflows and let terraform recreate them" + echo " Run: $0 $PROJECT_ID $REGION --delete" + echo "" + echo "Option B: Keep existing workflows (may cause deployment to fail)" + echo " Continue with deployment and handle errors manually" + echo "" + + # Check for --delete flag + if [ "$3" = "--delete" ]; then + echo "Deleting existing workflows..." + for workflow in "simulation-workflow" "wait-for-country-packages"; do + if echo "$EXISTING_WORKFLOWS" | grep -q "$workflow"; then + echo "Deleting $workflow..." + gcloud workflows delete "$workflow" --location="$REGION" --project="$PROJECT_ID" --quiet || true + fi + done + echo "✅ Workflows deleted. You can now run terraform deployment." + else + exit 1 + fi +else + echo "✅ No conflicting workflows found. Safe to proceed with terraform deployment." +fi \ No newline at end of file diff --git a/deployment/terraform/import-existing.sh b/deployment/terraform/import-existing.sh new file mode 100755 index 00000000..5cb76cbd --- /dev/null +++ b/deployment/terraform/import-existing.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# Script to import existing GCP resources into terraform state + +# Source environment +if [ -f "../.env" ]; then + export $(cat ../.env | grep -v '^#' | xargs) +fi + +PROJECT_ID="${PROJECT_ID:-beta-api-v2-1b3f}" +REGION="${REGION:-us-central1}" + +echo "Importing existing resources into terraform state for project: $PROJECT_ID" + +# Generate auto.tfvars file with required variables +US_VERSION=$(grep -A1 'name = "policyengine-us"' ../../projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') +UK_VERSION=$(grep -A1 'name = "policyengine-uk"' ../../projects/policyengine-api-simulation/uv.lock | grep version | head -1 | sed 's/.*"\(.*\)".*/\1/') +COMMIT_URL="https://github.com/PolicyEngine/policyengine-api-v2/commit/$(cd ../.. && git rev-parse HEAD)" + +cat > infra/auto.tfvars </dev/null || echo " workflow_sa already imported or doesn't exist" +terraform import -var-file=auto.tfvars module.cloud_run_tagger_api.google_service_account.api projects/$PROJECT_ID/serviceAccounts/tagger-api@$PROJECT_ID.iam.gserviceaccount.com 2>/dev/null || echo " tagger-api SA already imported or doesn't exist" +terraform import -var-file=auto.tfvars module.cloud_run_full_api.google_service_account.api projects/$PROJECT_ID/serviceAccounts/full-api@$PROJECT_ID.iam.gserviceaccount.com 2>/dev/null || echo " full-api SA already imported or doesn't exist" +terraform import -var-file=auto.tfvars module.cloud_run_simulation_api.google_service_account.api projects/$PROJECT_ID/serviceAccounts/api-simulation@$PROJECT_ID.iam.gserviceaccount.com 2>/dev/null || echo " api-simulation SA already imported or doesn't exist" + +echo "=== Importing IAM Roles ===" +terraform import -var-file=auto.tfvars google_project_iam_custom_role.cloudrun_service_updater projects/$PROJECT_ID/roles/cloudRunServiceUpdater 2>/dev/null || echo " Custom role already imported or doesn't exist" + +echo "=== Importing Storage Buckets ===" +terraform import -var-file=auto.tfvars google_storage_bucket.metadata $PROJECT_ID-metadata 2>/dev/null || echo " Metadata bucket already imported or doesn't exist" + +echo "=== Importing Cloud Run Services ===" +terraform import -var-file=auto.tfvars module.cloud_run_tagger_api.google_cloud_run_v2_service.api projects/$PROJECT_ID/locations/$REGION/services/tagger-api 2>/dev/null || echo " tagger-api service already imported or doesn't exist" +terraform import -var-file=auto.tfvars module.cloud_run_full_api.google_cloud_run_v2_service.api projects/$PROJECT_ID/locations/$REGION/services/full-api 2>/dev/null || echo " full-api service already imported or doesn't exist" +terraform import -var-file=auto.tfvars module.cloud_run_simulation_api.google_cloud_run_v2_service.api projects/$PROJECT_ID/locations/$REGION/services/api-simulation 2>/dev/null || echo " api-simulation service already imported or doesn't exist" + +echo "=== Handling Workflows ===" +echo "Note: Workflows don't support terraform import." +echo "If you see 'already exists' errors for workflows, you have two options:" +echo " 1. Delete the existing workflows manually and let terraform recreate them" +echo " 2. Import them into state manually (advanced)" + +# Check if workflows exist +if gcloud workflows list --location=$REGION --project=$PROJECT_ID 2>/dev/null | grep -q "wait-for-country-packages"; then + echo "⚠️ Found existing workflow: wait-for-country-packages" + echo " To resolve: gcloud workflows delete wait-for-country-packages --location=$REGION --project=$PROJECT_ID" +fi + +if gcloud workflows list --location=$REGION --project=$PROJECT_ID 2>/dev/null | grep -q "simulation-workflow"; then + echo "⚠️ Found existing workflow: simulation-workflow" + echo " To resolve: gcloud workflows delete simulation-workflow --location=$REGION --project=$PROJECT_ID" +fi + +echo "" +echo "✅ Import process complete!" +echo "" +echo "Next steps:" +echo " 1. If you see workflow conflicts above, delete them with the provided commands" +echo " 2. Run 'make terraform-deploy' to deploy/update infrastructure" \ No newline at end of file diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/py.typed b/deployment/terraform/infra/.github/workflows/ci.yml similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/py.typed rename to deployment/terraform/infra/.github/workflows/ci.yml diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/__init__.py b/deployment/terraform/infra/.github/workflows/deploy.yml similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/__init__.py rename to deployment/terraform/infra/.github/workflows/deploy.yml diff --git a/terraform/infra-policyengine-api/.gitignore b/deployment/terraform/infra/.gitignore similarity index 100% rename from terraform/infra-policyengine-api/.gitignore rename to deployment/terraform/infra/.gitignore diff --git a/terraform/infra-policyengine-api/apply.example.tfvars b/deployment/terraform/infra/apply.example.tfvars similarity index 100% rename from terraform/infra-policyengine-api/apply.example.tfvars rename to deployment/terraform/infra/apply.example.tfvars diff --git a/deployment/terraform/infra/backend.tf b/deployment/terraform/infra/backend.tf new file mode 100644 index 00000000..de335bac --- /dev/null +++ b/deployment/terraform/infra/backend.tf @@ -0,0 +1,6 @@ +terraform { + backend "gcs" { + bucket = "beta-api-v2-1b3f-state" + prefix = "infra" + } +} diff --git a/terraform/infra-policyengine-api/main.tf b/deployment/terraform/infra/main.tf similarity index 99% rename from terraform/infra-policyengine-api/main.tf rename to deployment/terraform/infra/main.tf index 01989d06..3324423d 100644 --- a/terraform/infra-policyengine-api/main.tf +++ b/deployment/terraform/infra/main.tf @@ -194,7 +194,7 @@ resource "google_workflows_workflow" "simulation_workflow" { service_path = "simulate/economy/comparison" # Separate path tagger_service_url = "${module.cloud_run_tagger_api.uri}" } - source_contents = file("../../projects/policyengine-api-simulation/workflow.yaml") + source_contents = file("../../../projects/policyengine-api-simulation/workflow.yaml") } # Grant the test service account permission to execute the workflow diff --git a/terraform/infra-policyengine-api/modules/fastapi_cloudrun/main.tf b/deployment/terraform/infra/modules/fastapi_cloudrun/main.tf similarity index 100% rename from terraform/infra-policyengine-api/modules/fastapi_cloudrun/main.tf rename to deployment/terraform/infra/modules/fastapi_cloudrun/main.tf diff --git a/terraform/infra-policyengine-api/modules/fastapi_cloudrun/monitoring.tf b/deployment/terraform/infra/modules/fastapi_cloudrun/monitoring.tf similarity index 100% rename from terraform/infra-policyengine-api/modules/fastapi_cloudrun/monitoring.tf rename to deployment/terraform/infra/modules/fastapi_cloudrun/monitoring.tf diff --git a/terraform/infra-policyengine-api/modules/fastapi_cloudrun/outputs.tf b/deployment/terraform/infra/modules/fastapi_cloudrun/outputs.tf similarity index 100% rename from terraform/infra-policyengine-api/modules/fastapi_cloudrun/outputs.tf rename to deployment/terraform/infra/modules/fastapi_cloudrun/outputs.tf diff --git a/terraform/infra-policyengine-api/modules/fastapi_cloudrun/variables.tf b/deployment/terraform/infra/modules/fastapi_cloudrun/variables.tf similarity index 100% rename from terraform/infra-policyengine-api/modules/fastapi_cloudrun/variables.tf rename to deployment/terraform/infra/modules/fastapi_cloudrun/variables.tf diff --git a/terraform/infra-policyengine-api/outputs.tf b/deployment/terraform/infra/outputs.tf similarity index 100% rename from terraform/infra-policyengine-api/outputs.tf rename to deployment/terraform/infra/outputs.tf diff --git a/terraform/infra-policyengine-api/variables.tf b/deployment/terraform/infra/variables.tf similarity index 100% rename from terraform/infra-policyengine-api/variables.tf rename to deployment/terraform/infra/variables.tf diff --git a/terraform/infra-policyengine-api/workflows/wait_for_country_versions.yaml b/deployment/terraform/infra/workflows/wait_for_country_versions.yaml similarity index 100% rename from terraform/infra-policyengine-api/workflows/wait_for_country_versions.yaml rename to deployment/terraform/infra/workflows/wait_for_country_versions.yaml diff --git a/terraform/project-policyengine-api/.gitignore b/deployment/terraform/project/.gitignore similarity index 100% rename from terraform/project-policyengine-api/.gitignore rename to deployment/terraform/project/.gitignore diff --git a/terraform/project-policyengine-api/apply.example.tfvars b/deployment/terraform/project/apply.example.tfvars similarity index 100% rename from terraform/project-policyengine-api/apply.example.tfvars rename to deployment/terraform/project/apply.example.tfvars diff --git a/terraform/project-policyengine-api/main.tf b/deployment/terraform/project/main.tf similarity index 100% rename from terraform/project-policyengine-api/main.tf rename to deployment/terraform/project/main.tf diff --git a/terraform/project-policyengine-api/outputs.tf b/deployment/terraform/project/outputs.tf similarity index 100% rename from terraform/project-policyengine-api/outputs.tf rename to deployment/terraform/project/outputs.tf diff --git a/terraform/project-policyengine-api/scripts/attach.sh b/deployment/terraform/project/scripts/attach.sh similarity index 100% rename from terraform/project-policyengine-api/scripts/attach.sh rename to deployment/terraform/project/scripts/attach.sh diff --git a/terraform/project-policyengine-api/scripts/bootstrap.sh b/deployment/terraform/project/scripts/bootstrap.sh similarity index 100% rename from terraform/project-policyengine-api/scripts/bootstrap.sh rename to deployment/terraform/project/scripts/bootstrap.sh diff --git a/terraform/project-policyengine-api/variables.tf b/deployment/terraform/project/variables.tf similarity index 100% rename from terraform/project-policyengine-api/variables.tf rename to deployment/terraform/project/variables.tf diff --git a/libs/policyengine-fastapi/Makefile b/libs/policyengine-fastapi/Makefile deleted file mode 100644 index 2c760893..00000000 --- a/libs/policyengine-fastapi/Makefile +++ /dev/null @@ -1 +0,0 @@ -include ../../common.mk diff --git a/libs/policyengine-fastapi/pyproject.toml b/libs/policyengine-fastapi/pyproject.toml index 0fbf79f4..7b875cca 100644 --- a/libs/policyengine-fastapi/pyproject.toml +++ b/libs/policyengine-fastapi/pyproject.toml @@ -31,11 +31,11 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] sources = ["src"] -only-include = ["src/policyengine_api/fastapi"] -packages = ["src/policyengine_api"] +only-include = ["src/policyengine_fastapi"] +packages = ["src/policyengine_fastapi"] [tool.pytest.ini_options] pythonpath = [ "src" ] -addopts = "--cov=policyengine_api.fastapi --cov-report=term-missing --cov-fail-under=30" +addopts = "--cov=policyengine_fastapi --cov-report=term-missing --cov-fail-under=30" diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/__init__.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/__init__.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/auth/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/auth/__init__.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/auth/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/auth/__init__.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/auth/jwt_decoder.py b/libs/policyengine-fastapi/src/policyengine_fastapi/auth/jwt_decoder.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/auth/jwt_decoder.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/auth/jwt_decoder.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/database.py b/libs/policyengine-fastapi/src/policyengine_fastapi/database.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/database.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/database.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/exit.py b/libs/policyengine-fastapi/src/policyengine_fastapi/exit.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/exit.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/exit.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/health/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/health/__init__.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/health/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/health/__init__.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/__init__.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/__init__.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/console.py b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/console.py similarity index 96% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/console.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/console.py index 980dba60..34c0475e 100644 --- a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/console.py +++ b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/console.py @@ -17,7 +17,7 @@ PeriodicExportingMetricReader, ConsoleMetricExporter, ) -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit # Configure opentelemetry diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/gcp.py b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/gcp.py similarity index 98% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/gcp.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/gcp.py index ea461d4f..442e3aad 100644 --- a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/gcp.py +++ b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/gcp.py @@ -10,7 +10,7 @@ from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit log = logging.getLogger(__name__) @@ -60,7 +60,6 @@ def _get_project_id_from_metadata() -> str | None: class GCPLoggingInstrumentor: - def __init__(self, project_id: str | None = None): self.project_id = project_id or _get_project_id() diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/instrumentor.py b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/instrumentor.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/instrumentor.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/instrumentor.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/middleware.py b/libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/middleware.py similarity index 100% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/opentelemetry/middleware.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/opentelemetry/middleware.py diff --git a/libs/policyengine-fastapi/src/policyengine_api/fastapi/ping/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/ping/__init__.py similarity index 94% rename from libs/policyengine-fastapi/src/policyengine_api/fastapi/ping/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/ping/__init__.py index 6cf9703d..877e93db 100644 --- a/libs/policyengine-fastapi/src/policyengine_api/fastapi/ping/__init__.py +++ b/libs/policyengine-fastapi/src/policyengine_fastapi/ping/__init__.py @@ -1,7 +1,7 @@ from fastapi import FastAPI, APIRouter from fastapi.responses import JSONResponse from pydantic import BaseModel -from policyengine_api.fastapi.health import HealthRegistry, HealthStatus +from policyengine_fastapi.health import HealthRegistry, HealthStatus class PingRequest(BaseModel): diff --git a/projects/policyengine-household-api/src/policyengine_household_api/__init__.py b/libs/policyengine-fastapi/src/policyengine_fastapi/py.typed similarity index 100% rename from projects/policyengine-household-api/src/policyengine_household_api/__init__.py rename to libs/policyengine-fastapi/src/policyengine_fastapi/py.typed diff --git a/libs/policyengine-fastapi/tests/ping/conftest.py b/libs/policyengine-fastapi/tests/ping/conftest.py index b6e52318..e5e76a92 100644 --- a/libs/policyengine-fastapi/tests/ping/conftest.py +++ b/libs/policyengine-fastapi/tests/ping/conftest.py @@ -2,8 +2,8 @@ import pytest from fastapi import FastAPI -from policyengine_api.fastapi import ping -from policyengine_api.fastapi.health import HealthRegistry +from policyengine_fastapi import ping +from policyengine_fastapi.health import HealthRegistry @pytest.fixture diff --git a/libs/policyengine-fastapi/tests/ping/test_alive.py b/libs/policyengine-fastapi/tests/ping/test_alive.py index 4d350bf2..b2f47139 100644 --- a/libs/policyengine-fastapi/tests/ping/test_alive.py +++ b/libs/policyengine-fastapi/tests/ping/test_alive.py @@ -1,5 +1,5 @@ from fastapi.testclient import TestClient -from policyengine_api.fastapi.health import ( +from policyengine_fastapi.health import ( HealthRegistry, HealthSystemReporter, ProbeStatus, diff --git a/libs/policyengine-fastapi/tests/test_exit.py b/libs/policyengine-fastapi/tests/test_exit.py index 930b196e..c159a7b9 100644 --- a/libs/policyengine-fastapi/tests/test_exit.py +++ b/libs/policyengine-fastapi/tests/test_exit.py @@ -1,5 +1,5 @@ from unittest.mock import Mock, call -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit import pytest diff --git a/libs/policyengine-fastapi/uv.lock b/libs/policyengine-fastapi/uv.lock index f35eda75..71d9aa90 100644 --- a/libs/policyengine-fastapi/uv.lock +++ b/libs/policyengine-fastapi/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13" [[package]] @@ -1037,7 +1037,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1045,9 +1045,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -1200,7 +1200,7 @@ wheels = [ [[package]] name = "typer" -version = "0.16.0" +version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1208,9 +1208,9 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, + { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, ] [[package]] diff --git a/projects/policyengine-api-full/Dockerfile b/projects/policyengine-api-full/Dockerfile index df924047..c4e71532 100644 --- a/projects/policyengine-api-full/Dockerfile +++ b/projects/policyengine-api-full/Dockerfile @@ -1,25 +1,32 @@ -FROM python:3.13-slim +# Multi-stage build inheriting from base +# Use explicit platform for consistency across builds +FROM --platform=linux/amd64 python:3.13-slim AS base + +# Install uv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -# Set environment variables -ENV ENVIRONMENT="production" \ - JWT_ISSUER=https://your_production_issuer/ \ - JWT_AUDIENCE=https://your_production_api/ \ - OT_SERVICE_NAME=policyengine_full_api \ - OT_SERVICE_INSTANCE_ID=instance +# Set common environment variables +ENV ENVIRONMENT="production" WORKDIR /app -# Copy LICENSE file to the root where it's expected +# Copy shared libraries and LICENSE COPY LICENSE ./LICENSE +COPY libs ./libs/ + +# Final stage +FROM base AS final + +# Service-specific environment +ENV OT_SERVICE_NAME=policyengine_full_api \ + OT_SERVICE_INSTANCE_ID=instance -# Copy the entire project structure for dependencies -COPY libs/policyengine-fastapi ./libs/policyengine-fastapi/ +# Copy service-specific code COPY projects/policyengine-api-full ./projects/policyengine-api-full/ WORKDIR /app/projects/policyengine-api-full -# Install dependencies using uv +# Install dependencies RUN uv sync --frozen --no-dev EXPOSE 8080 diff --git a/projects/policyengine-api-full/Makefile b/projects/policyengine-api-full/Makefile deleted file mode 100644 index 87ea006c..00000000 --- a/projects/policyengine-api-full/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Define custom targets before including common.mk -HAS_CUSTOM_GENERATE := 1 -HAS_CUSTOM_PYRIGHT := 1 - -include ./makefile.env -include ../../server_common.local.mk - -generate: - cd src && python -m policyengine_api_full.generate_openapi - python ./generate_clients.py - -pyright: - $(Q)$(HELPER) subtask "Type checking" "echo 'Skipping - see issue #271'" diff --git a/projects/policyengine-api-full/Makefile.deploy b/projects/policyengine-api-full/Makefile.deploy deleted file mode 100644 index 551ba839..00000000 --- a/projects/policyengine-api-full/Makefile.deploy +++ /dev/null @@ -1,2 +0,0 @@ -include makefile.env -include ../../server_common.deploy.mk diff --git a/projects/policyengine-api-full/generate_clients.py b/projects/policyengine-api-full/generate_clients.py deleted file mode 100755 index 87538564..00000000 --- a/projects/policyengine-api-full/generate_clients.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -"""Generate OpenAPI clients using openapi-python-client and openapi-typescript-codegen.""" - -import subprocess -import sys -from pathlib import Path - - -def generate_python_client(): - """Generate Python client from OpenAPI spec.""" - project_dir = Path(__file__).parent - spec_path = project_dir / "artifacts" / "openapi.json" - output_dir = project_dir / "artifacts" / "clients" / "python" - - if not spec_path.exists(): - print(f"Error: OpenAPI spec not found at {spec_path}") - return False - - # Ensure output directory exists - output_dir.parent.mkdir(parents=True, exist_ok=True) - - # Generate the client (dependencies already installed by Makefile) - print(f"Generating Python client from {spec_path}...") - cmd = [ - "uv", - "run", - "--active", - "openapi-python-client", - "generate", - "--path", - str(spec_path), - "--output-path", - str(output_dir), - "--overwrite", - ] - - result = subprocess.run(cmd, capture_output=True, text=True, cwd=project_dir) - - if result.returncode != 0: - print(f"Error generating Python client: {result.stderr}") - return False - - print(f"Successfully generated Python client in {output_dir}") - print(result.stdout) - return True - - -def main(): - """Generate all clients.""" - success = True - - if not generate_python_client(): - success = False - - if not success: - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/projects/policyengine-api-full/makefile.env b/projects/policyengine-api-full/makefile.env deleted file mode 100644 index 7d7ab120..00000000 --- a/projects/policyengine-api-full/makefile.env +++ /dev/null @@ -1,3 +0,0 @@ -SERVICE_NAME=policyengine-api-full -MODULE_NAME=policyengine_api_full.main -DEV_PORT=8080 diff --git a/projects/policyengine-api-full/pyproject.toml b/projects/policyengine-api-full/pyproject.toml index a0a1775f..b45c6142 100644 --- a/projects/policyengine-api-full/pyproject.toml +++ b/projects/policyengine-api-full/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ ] [tool.hatch.build.targets.wheel] -packages = ["src/policyengine_api_full", "src/policyengine_api"] +packages = ["src/policyengine_api_full"] [tool.uv.sources] policyengine-fastapi = { path = "../../libs/policyengine-fastapi", editable = true } @@ -34,4 +34,4 @@ pythonpath = [ "src", ] testpaths = ["tests"] -addopts = "--cov=policyengine_api --cov-report=term-missing --cov-fail-under=80" +addopts = "--cov=policyengine_api_full --cov-report=term-missing" diff --git a/projects/policyengine-api-full/src/policyengine_api/api/__init__.py b/projects/policyengine-api-full/src/policyengine_api_full/api/__init__.py similarity index 86% rename from projects/policyengine-api-full/src/policyengine_api/api/__init__.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/__init__.py index 0b880429..0f3c38b4 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/__init__.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/__init__.py @@ -1,8 +1,8 @@ from fastapi import FastAPI from sqlalchemy import Engine -from policyengine_api.fastapi.auth.jwt_decoder import JWTDecoder -from policyengine_api.fastapi.database import create_session_dep +from policyengine_fastapi.auth.jwt_decoder import JWTDecoder +from policyengine_fastapi.database import create_session_dep from .household import include_all_routers """ diff --git a/projects/policyengine-api-full/src/policyengine_api/api/country.py b/projects/policyengine-api-full/src/policyengine_api_full/api/country.py similarity index 96% rename from projects/policyengine-api-full/src/policyengine_api/api/country.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/country.py index 9554cad3..38f32564 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/country.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/country.py @@ -5,37 +5,37 @@ from policyengine_core.variables import Variable as CoreVariable from policyengine_core.simulations import Simulation from policyengine_core.populations import Population -from policyengine_api.api.utils.constants import CURRENT_LAW_IDS -from policyengine_api.api.utils.json import get_safe_json -from policyengine_api.api.utils.metadata import ( +from policyengine_api_full.api.utils.constants import CURRENT_LAW_IDS +from policyengine_api_full.api.utils.json import get_safe_json +from policyengine_api_full.api.utils.metadata import ( parse_enum_possible_values, parse_default_value, ) -from policyengine_api.api.models.household import ( +from policyengine_api_full.api.models.household import ( HouseholdUS, HouseholdUK, HouseholdGeneric, ) -from policyengine_api.api.models.metadata.variable import ( +from policyengine_api_full.api.models.metadata.variable import ( Variable, VariableModule, ) -from policyengine_api.api.models.metadata.entity import Entity -from policyengine_api.api.models.metadata.modeled_policies import ( +from policyengine_api_full.api.models.metadata.entity import Entity +from policyengine_api_full.api.models.metadata.modeled_policies import ( ModeledPolicies, ) -from policyengine_api.api.models.metadata.economy_options import ( +from policyengine_api_full.api.models.metadata.economy_options import ( Region, TimePeriod, EconomyOptions, ) -from policyengine_api.api.models.metadata.parameter import ( +from policyengine_api_full.api.models.metadata.parameter import ( ParameterScaleItem, ParameterNode, Parameter, ) -from policyengine_api.api.models.metadata.metadata_module import MetadataModule -from policyengine_api.api.models.periods import ISO8601Date +from policyengine_api_full.api.models.metadata.metadata_module import MetadataModule +from policyengine_api_full.api.models.periods import ISO8601Date from typing import Union, Any from numpy.typing import ArrayLike @@ -134,7 +134,6 @@ def _build_parameters( ] = system.parameters parameter_data = {} for parameter in parameters.get_descendants(): - # Only include parameters from approved folders if not any( parameter.name.startswith(folder) @@ -167,7 +166,6 @@ def _build_entities(self, system: TaxBenefitSystem) -> dict[str, Entity]: data = {} for entity in entities: - roles = {} if hasattr(entity, "roles"): roles = { diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/regions/ca_regions.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/ca_regions.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/regions/ca_regions.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/ca_regions.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/regions/il_regions.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/il_regions.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/regions/il_regions.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/il_regions.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/regions/ng_regions.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/ng_regions.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/regions/ng_regions.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/ng_regions.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/regions/uk_regions.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/uk_regions.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/regions/uk_regions.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/uk_regions.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/regions/us_regions.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/us_regions.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/regions/us_regions.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/regions/us_regions.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/default_time_periods.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/default_time_periods.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/default_time_periods.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/default_time_periods.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/uk_time_periods.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/uk_time_periods.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/uk_time_periods.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/uk_time_periods.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/us_time_periods.json b/projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/us_time_periods.json similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/data/time_periods/us_time_periods.json rename to projects/policyengine-api-full/src/policyengine_api_full/api/data/time_periods/us_time_periods.json diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/__init__.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/__init__.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/__init__.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/__init__.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/country_id.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/country_id.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/country_id.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/country_id.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/entities.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/entities.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/entities.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/entities.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/entity_groups.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/entity_groups.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/entity_groups.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/entity_groups.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/periods.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/periods.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/periods.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/periods.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/enums/value_types.py b/projects/policyengine-api-full/src/policyengine_api_full/api/enums/value_types.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/enums/value_types.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/enums/value_types.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/household/__init__.py b/projects/policyengine-api-full/src/policyengine_api_full/api/household/__init__.py similarity index 80% rename from projects/policyengine-api-full/src/policyengine_api/api/household/__init__.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/household/__init__.py index 3570c581..1acbab99 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/household/__init__.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/household/__init__.py @@ -1,8 +1,8 @@ from fastapi import FastAPI -from policyengine_api.fastapi.auth.jwt_decoder import JWTDecoder +from policyengine_fastapi.auth.jwt_decoder import JWTDecoder from .household import create_router as create_household_router from .user import create_router as create_user_router -from policyengine_api.fastapi.database import SessionGeneratorFactory +from policyengine_fastapi.database import SessionGeneratorFactory def include_all_routers( diff --git a/projects/policyengine-api-full/src/policyengine_api/api/household/household.py b/projects/policyengine-api-full/src/policyengine_api_full/api/household/household.py similarity index 91% rename from projects/policyengine-api-full/src/policyengine_api/api/household/household.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/household/household.py index 03f9f9ca..675b15c6 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/household/household.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/household/household.py @@ -1,7 +1,7 @@ from typing import Annotated from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session, SQLModel, Field -from policyengine_api.fastapi.database import SessionGeneratorFactory +from policyengine_fastapi.database import SessionGeneratorFactory class HouseholdBase(SQLModel): @@ -9,7 +9,7 @@ class HouseholdBase(SQLModel): class Household(HouseholdBase, table=True): - id: int | None = Field(default=None, primary_key=True) + id: int | None = Field(None, primary_key=True) class HouseholdCreate(HouseholdBase): diff --git a/projects/policyengine-api-full/src/policyengine_api/api/household/user.py b/projects/policyengine-api-full/src/policyengine_api_full/api/household/user.py similarity index 93% rename from projects/policyengine-api-full/src/policyengine_api/api/household/user.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/household/user.py index ba5779e3..1af07af7 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/household/user.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/household/user.py @@ -3,8 +3,8 @@ from fastapi.security import HTTPAuthorizationCredentials from pydantic import BaseModel from sqlmodel import Field, SQLModel, Session -from policyengine_api.fastapi.database import SessionGeneratorFactory -from policyengine_api.fastapi.auth import JWTDecoder +from policyengine_fastapi.database import SessionGeneratorFactory +from policyengine_fastapi.auth import JWTDecoder import logging # Use standard python logging @@ -16,13 +16,13 @@ # SQLModel models class UserBase(SQLModel): - username: str + username: str = Field(..., description="Username") pass class User(UserBase, table=True): - id: int | None = Field(default=None, primary_key=True) - auth0_sub: str + id: int | None = Field(None, primary_key=True) + auth0_sub: str = Field(..., description="Auth0 subject identifier") # Request/Response Models diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/household.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/household.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/household.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/household.py diff --git a/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/__init__.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/economy_options.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/economy_options.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/economy_options.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/economy_options.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/entity.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/entity.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/entity.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/entity.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/metadata_module.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/metadata_module.py similarity index 60% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/metadata_module.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/metadata_module.py index ac886fae..1f3e8ad5 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/metadata_module.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/metadata_module.py @@ -1,16 +1,16 @@ from pydantic import BaseModel from typing import Optional -from policyengine_api.api.models.metadata.entity import Entity -from policyengine_api.api.models.metadata.economy_options import EconomyOptions -from policyengine_api.api.models.metadata.modeled_policies import ( +from policyengine_api_full.api.models.metadata.entity import Entity +from policyengine_api_full.api.models.metadata.economy_options import EconomyOptions +from policyengine_api_full.api.models.metadata.modeled_policies import ( ModeledPolicies, ) -from policyengine_api.api.models.metadata.parameter import ( +from policyengine_api_full.api.models.metadata.parameter import ( Parameter, ParameterNode, ParameterScaleItem, ) -from policyengine_api.api.models.metadata.variable import ( +from policyengine_api_full.api.models.metadata.variable import ( Variable, VariableModule, ) diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/modeled_policies.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/modeled_policies.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/modeled_policies.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/modeled_policies.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/parameter.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/parameter.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/parameter.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/parameter.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/variable.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/variable.py similarity index 95% rename from projects/policyengine-api-full/src/policyengine_api/api/models/metadata/variable.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/variable.py index 3218766e..c887a535 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/models/metadata/variable.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/models/metadata/variable.py @@ -1,6 +1,6 @@ from pydantic import BaseModel from typing import Any, Optional -from policyengine_api.api.enums import ( +from policyengine_api_full.api.enums import ( PERIODS, VALUE_TYPES, ENTITIES_US, diff --git a/projects/policyengine-api-full/src/policyengine_api/api/models/periods.py b/projects/policyengine-api-full/src/policyengine_api_full/api/models/periods.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/models/periods.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/models/periods.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/routers/calculate.py b/projects/policyengine-api-full/src/policyengine_api_full/api/routers/calculate.py similarity index 83% rename from projects/policyengine-api-full/src/policyengine_api/api/routers/calculate.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/routers/calculate.py index fc7a0888..cc6af662 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/routers/calculate.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/routers/calculate.py @@ -1,12 +1,12 @@ from fastapi import APIRouter, Body -from policyengine_api.api.enums import COUNTRY_ID -from policyengine_api.api.models.household import ( +from policyengine_api_full.api.enums import COUNTRY_ID +from policyengine_api_full.api.models.household import ( HouseholdUS, HouseholdUK, HouseholdGeneric, example_household_input_us, ) -from policyengine_api.api.country import COUNTRIES +from policyengine_api_full.api.country import COUNTRIES from typing import Annotated @@ -21,7 +21,6 @@ async def calculate( Body(examples=[example_household_input_us], embed=True), ], ) -> HouseholdGeneric | HouseholdUK | HouseholdUS: - # Household models above currently conflict with models defined in # household/household.py; the household routes will be brought in # line in later iteration diff --git a/projects/policyengine-api-full/src/policyengine_api/api/routers/metadata.py b/projects/policyengine-api-full/src/policyengine_api_full/api/routers/metadata.py similarity index 54% rename from projects/policyengine-api-full/src/policyengine_api/api/routers/metadata.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/routers/metadata.py index b868807d..9ed57617 100644 --- a/projects/policyengine-api-full/src/policyengine_api/api/routers/metadata.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/api/routers/metadata.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, Depends -from policyengine_api.api.enums import COUNTRY_ID -from policyengine_api.api.models.metadata.metadata_module import MetadataModule -from policyengine_api.api.country import COUNTRIES +from policyengine_api_full.api.enums import COUNTRY_ID +from policyengine_api_full.api.models.metadata.metadata_module import MetadataModule +from policyengine_api_full.api.country import COUNTRIES router = APIRouter() diff --git a/projects/policyengine-api-full/src/policyengine_api/api/utils/__init__.py b/projects/policyengine-api-full/src/policyengine_api_full/api/utils/__init__.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/utils/__init__.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/utils/__init__.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/utils/constants.py b/projects/policyengine-api-full/src/policyengine_api_full/api/utils/constants.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/utils/constants.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/utils/constants.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/utils/json.py b/projects/policyengine-api-full/src/policyengine_api_full/api/utils/json.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/utils/json.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/utils/json.py diff --git a/projects/policyengine-api-full/src/policyengine_api/api/utils/metadata.py b/projects/policyengine-api-full/src/policyengine_api_full/api/utils/metadata.py similarity index 100% rename from projects/policyengine-api-full/src/policyengine_api/api/utils/metadata.py rename to projects/policyengine-api-full/src/policyengine_api_full/api/utils/metadata.py diff --git a/projects/policyengine-api-full/src/policyengine_api_full/main.py b/projects/policyengine-api-full/src/policyengine_api_full/main.py index 0ae36aa4..c059325e 100644 --- a/projects/policyengine-api-full/src/policyengine_api_full/main.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/main.py @@ -2,15 +2,15 @@ from typing import Any from fastapi import FastAPI from sqlmodel import SQLModel -from policyengine_api.fastapi.database import create_sqlite_engine -from policyengine_api.fastapi import ping -from policyengine_api.fastapi.health import ( +from policyengine_fastapi.database import create_sqlite_engine +from policyengine_fastapi import ping +from policyengine_fastapi.health import ( HealthRegistry, HealthSystemReporter, ) -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit from .settings import get_settings, Environment -from policyengine_api.fastapi.opentelemetry import ( +from policyengine_fastapi.opentelemetry import ( GCPLoggingInstrumentor, FastAPIEnhancedInstrumenter, export_ot_to_console, @@ -22,7 +22,7 @@ Resource, ) from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor -from policyengine_api.api import initialize +from policyengine_api_full.api import initialize import logging """ @@ -81,7 +81,7 @@ async def lifespan(app: FastAPI): } ) -match (get_settings().environment): +match get_settings().environment: case Environment.DESKTOP: pass # export_ot_to_console(resource) case Environment.PRODUCTION: diff --git a/projects/policyengine-api-full/src/policyengine_api_full/settings.py b/projects/policyengine-api-full/src/policyengine_api_full/settings.py index e8f8bc8d..aed9b822 100644 --- a/projects/policyengine-api-full/src/policyengine_api_full/settings.py +++ b/projects/policyengine-api-full/src/policyengine_api_full/settings.py @@ -1,6 +1,7 @@ from enum import Enum from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict +from pydantic import field_validator class Environment(Enum): @@ -11,6 +12,13 @@ class Environment(Enum): class AppSettings(BaseSettings): environment: Environment = Environment.DESKTOP + @field_validator("environment", mode="before") + @classmethod + def strip_environment(cls, v): + if isinstance(v, str): + return v.strip() + return v + jwt_issuer: str = "https://your_issuer/" """ The issuer that must sign any JWT bearer token before the API with accept it as valid diff --git a/projects/policyengine-api-full/tests/api/household/test_household.py b/projects/policyengine-api-full/tests/api/household/test_household.py index 866df2ba..5e2a142c 100644 --- a/projects/policyengine-api-full/tests/api/household/test_household.py +++ b/projects/policyengine-api-full/tests/api/household/test_household.py @@ -1,9 +1,9 @@ from sqlmodel import SQLModel -from policyengine_api.fastapi.database import create_session_dep +from policyengine_fastapi.database import create_session_dep from ...common.fixtures import createApi, engine from fastapi.testclient import TestClient -from policyengine_api.api.household import create_household_router +from policyengine_api_full.api.household import create_household_router import pytest diff --git a/projects/policyengine-api-full/tests/api/household/test_user.py b/projects/policyengine-api-full/tests/api/household/test_user.py index f7971f72..44aa2855 100644 --- a/projects/policyengine-api-full/tests/api/household/test_user.py +++ b/projects/policyengine-api-full/tests/api/household/test_user.py @@ -5,9 +5,9 @@ import pytest from sqlmodel import SQLModel from ...common.fixtures import createApi, engine -from policyengine_api.api.household import create_user_router +from policyengine_api_full.api.household import create_user_router from pydantic_core import from_json -from policyengine_api.fastapi.database import create_session_dep +from policyengine_fastapi.database import create_session_dep def auth_override( diff --git a/projects/policyengine-api-full/tests/common/fixtures.py b/projects/policyengine-api-full/tests/common/fixtures.py index 70dbcd97..43e3c39f 100644 --- a/projects/policyengine-api-full/tests/common/fixtures.py +++ b/projects/policyengine-api-full/tests/common/fixtures.py @@ -1,7 +1,7 @@ from typing import Annotated from fastapi import APIRouter, Depends, FastAPI -from policyengine_api.fastapi.database import create_sqlite_engine +from policyengine_fastapi.database import create_sqlite_engine engine = create_sqlite_engine() diff --git a/projects/policyengine-api-full/uv.lock b/projects/policyengine-api-full/uv.lock index b4a939f7..abe8e463 100644 --- a/projects/policyengine-api-full/uv.lock +++ b/projects/policyengine-api-full/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13" [[package]] @@ -1121,7 +1121,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1129,9 +1129,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -1207,14 +1207,14 @@ wheels = [ [[package]] name = "ruamel-yaml" -version = "0.18.14" +version = "0.18.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ruamel-yaml-clib", marker = "python_full_version < '3.14' and platform_python_implementation == 'CPython'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/87/6da0df742a4684263261c253f00edd5829e6aca970fff69e75028cccc547/ruamel.yaml-0.18.14.tar.gz", hash = "sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7", size = 145511, upload-time = "2025-06-09T08:51:09.828Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/db/f3950f5e5031b618aae9f423a39bf81a55c148aecd15a34527898e752cf4/ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700", size = 146865, upload-time = "2025-08-19T11:15:10.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/6d/6fe4805235e193aad4aaf979160dd1f3c487c57d48b810c816e6e842171b/ruamel.yaml-0.18.14-py3-none-any.whl", hash = "sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2", size = 118570, upload-time = "2025-06-09T08:51:06.348Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/f2a0621f1781b76a38194acae72f01e37b1941470407345b6e8653ad7640/ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701", size = 119702, upload-time = "2025-08-19T11:15:07.696Z" }, ] [[package]] @@ -1348,7 +1348,7 @@ wheels = [ [[package]] name = "typer" -version = "0.16.0" +version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1356,9 +1356,9 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, + { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, ] [[package]] diff --git a/projects/policyengine-api-simulation/Dockerfile b/projects/policyengine-api-simulation/Dockerfile index 09f82da8..1dd135d1 100644 --- a/projects/policyengine-api-simulation/Dockerfile +++ b/projects/policyengine-api-simulation/Dockerfile @@ -1,26 +1,35 @@ -FROM python:3.13-slim +# Multi-stage build inheriting from base +# Use explicit platform for consistency across builds +FROM --platform=linux/amd64 python:3.13-slim AS base + +# Install uv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -# Set environment variables -ENV ENVIRONMENT="production" \ - OT_SERVICE_NAME=policyengine_simulation_api \ - OT_SERVICE_INSTANCE_ID=instance +# Set common environment variables +ENV ENVIRONMENT="production" WORKDIR /app -# Copy LICENSE file to the root where it's expected +# Copy shared libraries and LICENSE COPY LICENSE ./LICENSE +COPY libs ./libs/ + +# Final stage +FROM base AS final + +# Service-specific environment +ENV OT_SERVICE_NAME=policyengine_simulation_api \ + OT_SERVICE_INSTANCE_ID=instance -# Copy the entire project structure for dependencies -COPY libs/policyengine-fastapi ./libs/policyengine-fastapi/ +# Copy service-specific code COPY projects/policyengine-api-simulation ./projects/policyengine-api-simulation/ WORKDIR /app/projects/policyengine-api-simulation -# Install dependencies using uv +# Install dependencies RUN uv sync --frozen --no-dev EXPOSE 8080 -# Run with uvicorn +# Run with uvicorn (with 2 workers for simulation API) CMD ["uv", "run", "uvicorn", "policyengine_api_simulation.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "2"] \ No newline at end of file diff --git a/projects/policyengine-api-simulation/Makefile b/projects/policyengine-api-simulation/Makefile deleted file mode 100644 index 6350eef4..00000000 --- a/projects/policyengine-api-simulation/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Define custom targets before including common.mk -HAS_CUSTOM_GENERATE := 1 -HAS_CUSTOM_TEST := 1 - -include ./makefile.env -include ../../server_common.local.mk - -generate: - cd src && python -m policyengine_api_simulation.generate_openapi - python ./generate_clients.py - -test: - $(Q)$(HELPER) subtask "Running tests" "echo 'No tests configured for simulation API'" diff --git a/projects/policyengine-api-simulation/Makefile.deploy b/projects/policyengine-api-simulation/Makefile.deploy deleted file mode 100644 index 551ba839..00000000 --- a/projects/policyengine-api-simulation/Makefile.deploy +++ /dev/null @@ -1,2 +0,0 @@ -include makefile.env -include ../../server_common.deploy.mk diff --git a/projects/policyengine-api-simulation/generate_clients.py b/projects/policyengine-api-simulation/generate_clients.py deleted file mode 100755 index 04e4695c..00000000 --- a/projects/policyengine-api-simulation/generate_clients.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -"""Generate OpenAPI clients using openapi-python-client.""" - -import subprocess -import sys -from pathlib import Path - - -def generate_python_client(): - """Generate Python client from OpenAPI spec.""" - project_dir = Path(__file__).parent - spec_path = project_dir / "artifacts" / "openapi.json" - output_dir = project_dir / "artifacts" / "clients" / "python" - - if not spec_path.exists(): - print(f"Error: OpenAPI spec not found at {spec_path}") - sys.exit(1) - - # Ensure output directory exists - output_dir.parent.mkdir(parents=True, exist_ok=True) - - # Generate the client (dependencies already installed by Makefile) - print(f"Generating Python client from {spec_path}...") - cmd = [ - "uv", - "run", - "--active", - "openapi-python-client", - "generate", - "--path", - str(spec_path), - "--output-path", - str(output_dir), - "--overwrite", - ] - - result = subprocess.run(cmd, capture_output=True, text=True, cwd=project_dir) - - if result.returncode != 0: - print(f"Error generating client: {result.stderr}") - sys.exit(1) - - print(f"Successfully generated Python client in {output_dir}") - print(result.stdout) - - -if __name__ == "__main__": - generate_python_client() diff --git a/projects/policyengine-api-simulation/makefile.env b/projects/policyengine-api-simulation/makefile.env deleted file mode 100644 index 9aa5014b..00000000 --- a/projects/policyengine-api-simulation/makefile.env +++ /dev/null @@ -1,4 +0,0 @@ -SERVICE_NAME=policyengine-api-simulation -MODULE_NAME=policyengine_api_simulation.main -DEV_PORT=8081 -WORKER_COUNT=2 diff --git a/projects/policyengine-api-simulation/src/policyengine_api/simulation_api/__init__.py b/projects/policyengine-api-simulation/src/policyengine_api/simulation_api/__init__.py deleted file mode 100644 index e746e661..00000000 --- a/projects/policyengine-api-simulation/src/policyengine_api/simulation_api/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from fastapi import FastAPI -from .simulation import create_router - -""" -Application defined as routers completely indipendent of environment allowing it -to easily be run in whatever cloud provider container or desktop or test environment. -""" - - -def initialize(app: FastAPI): - """ - attach all routes to the app and configure them to use the provided SQLModel engine - and jwt settings. - """ - app.include_router(create_router()) diff --git a/projects/policyengine-api-simulation/src/policyengine_api_simulation/__init__.py b/projects/policyengine-api-simulation/src/policyengine_api_simulation/__init__.py index e69de29b..e746e661 100644 --- a/projects/policyengine-api-simulation/src/policyengine_api_simulation/__init__.py +++ b/projects/policyengine-api-simulation/src/policyengine_api_simulation/__init__.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI +from .simulation import create_router + +""" +Application defined as routers completely indipendent of environment allowing it +to easily be run in whatever cloud provider container or desktop or test environment. +""" + + +def initialize(app: FastAPI): + """ + attach all routes to the app and configure them to use the provided SQLModel engine + and jwt settings. + """ + app.include_router(create_router()) diff --git a/projects/policyengine-api-simulation/src/policyengine_api_simulation/main.py b/projects/policyengine-api-simulation/src/policyengine_api_simulation/main.py index 070cbd87..31a7eb82 100644 --- a/projects/policyengine-api-simulation/src/policyengine_api_simulation/main.py +++ b/projects/policyengine-api-simulation/src/policyengine_api_simulation/main.py @@ -2,21 +2,21 @@ from typing import Any from fastapi import FastAPI from .settings import get_settings, Environment -from policyengine_api.fastapi.opentelemetry import ( +from policyengine_fastapi.opentelemetry import ( GCPLoggingInstrumentor, FastAPIEnhancedInstrumenter, export_ot_to_console, export_ot_to_gcp, ) -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit from opentelemetry.sdk.resources import ( SERVICE_NAME, SERVICE_INSTANCE_ID, Resource, ) -from policyengine_api.simulation_api import initialize -from policyengine_api.fastapi import ping -from policyengine_api.fastapi.health import ( +from policyengine_api_simulation import initialize +from policyengine_fastapi import ping +from policyengine_fastapi.health import ( HealthRegistry, HealthSystemReporter, ) @@ -63,7 +63,7 @@ async def lifespan(app: FastAPI): } ) -match (get_settings().environment): +match get_settings().environment: case Environment.DESKTOP: pass # Don't print opentelemetry to console- this makes it impossible to read the logs. Alternatively, do by uncommenting this line. # export_ot_to_console(resource) diff --git a/projects/policyengine-api-simulation/src/policyengine_api_simulation/settings.py b/projects/policyengine-api-simulation/src/policyengine_api_simulation/settings.py index 90abfd3d..09c3407d 100644 --- a/projects/policyengine-api-simulation/src/policyengine_api_simulation/settings.py +++ b/projects/policyengine-api-simulation/src/policyengine_api_simulation/settings.py @@ -1,6 +1,7 @@ from enum import Enum from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict +from pydantic import field_validator class Environment(Enum): @@ -10,6 +11,14 @@ class Environment(Enum): class AppSettings(BaseSettings): environment: Environment = Environment.DESKTOP + + @field_validator("environment", mode="before") + @classmethod + def strip_environment(cls, v): + if isinstance(v, str): + return v.strip() + return v + ot_service_name: str = "YOUR_OT_SERVICE_NAME" """ service name used by opentelemetry when reporting trace information diff --git a/projects/policyengine-api-simulation/src/policyengine_api/simulation_api/simulation.py b/projects/policyengine-api-simulation/src/policyengine_api_simulation/simulation.py similarity index 100% rename from projects/policyengine-api-simulation/src/policyengine_api/simulation_api/simulation.py rename to projects/policyengine-api-simulation/src/policyengine_api_simulation/simulation.py diff --git a/projects/policyengine-api-simulation/tests/test_placeholder.py b/projects/policyengine-api-simulation/tests/test_placeholder.py new file mode 100644 index 00000000..d7c78f91 --- /dev/null +++ b/projects/policyengine-api-simulation/tests/test_placeholder.py @@ -0,0 +1,6 @@ +"""Placeholder test to ensure test suite runs.""" + + +def test_placeholder(): + """Placeholder test that always passes.""" + assert True \ No newline at end of file diff --git a/projects/policyengine-api-simulation/uv.lock b/projects/policyengine-api-simulation/uv.lock index 103e7ce5..cbb04e5f 100644 --- a/projects/policyengine-api-simulation/uv.lock +++ b/projects/policyengine-api-simulation/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13" [[package]] @@ -73,7 +73,7 @@ wheels = [ [[package]] name = "blosc2" -version = "3.7.1" +version = "3.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "msgpack" }, @@ -84,23 +84,23 @@ dependencies = [ { name = "py-cpuinfo", marker = "platform_machine != 'wasm32'" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/97/11ded041c0877e7e43658233619f60587dc52371cb6863af0fd01c7001a3/blosc2-3.7.1.tar.gz", hash = "sha256:ea1be4c4a03af018f6a912596d46ca215f0b84de5dd5acee4f750161847c6dcf", size = 3804381, upload-time = "2025-08-17T11:06:52.201Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ba/c1d8a8303197d8d8d4ec9b83851fcabd2d57dc5d17af2406643dd015544e/blosc2-3.7.2.tar.gz", hash = "sha256:3e80bd0399241829e4a2100bef9d4de042da979514f5df6aa3378981823f1d9b", size = 3804422, upload-time = "2025-08-19T10:21:46.164Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/a7/2d458bc23e71d013c685987dd3ed77ee124c5223127ff98a1ef17ee6563b/blosc2-3.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:03388169cc5ac54f79a2cbac7c62e5094c34a748718477dbebeb855dc24090f6", size = 3955853, upload-time = "2025-08-17T11:06:28.16Z" }, - { url = "https://files.pythonhosted.org/packages/1e/eb/007a53c9da82951cc379ed587a7b5f9d2002473677b5a3c5a8d5d5c525e5/blosc2-3.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f710a45f9b8e397c40f37be77a4f57f8d005d81043df6ef958a25a9097455cde", size = 3422480, upload-time = "2025-08-17T11:06:30.09Z" }, - { url = "https://files.pythonhosted.org/packages/84/fe/ccae0b8691da454d0e315f93d8a5cf246b23caf29b2bcaeb25456c7c597b/blosc2-3.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dbb425b580e91a384e131d3acc849e73a74cd65a00ae6daf3f4d43018623fcf5", size = 4309093, upload-time = "2025-08-17T11:06:31.419Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3d/1b0e5f1e1d72789c866d05242f630d269f6ee19eb759be9e22fa484fbb1a/blosc2-3.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2db87eb8cc4664ef6d31b12aa081b8a6f98c985c8687386ecf9d318fe956870d", size = 4448099, upload-time = "2025-08-17T11:06:33.35Z" }, - { url = "https://files.pythonhosted.org/packages/b5/ac/ac9e2ab021c77f583f7276aa810ea394391be481be2a6547ab44cfb63fa8/blosc2-3.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:2d0d4b88bd671244181f9cdb79415279860e88b0bd4f4abf935a0b4f3822b660", size = 2241602, upload-time = "2025-08-17T11:06:34.643Z" }, - { url = "https://files.pythonhosted.org/packages/86/76/94b22dd5a1b904a8ffecf3b65257a288b051996ce1689c022bba17c5f782/blosc2-3.7.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ca8f0510e7ec5e70852ae5f50f5cd1f9814c365c7d503afaef760b2c780f24b2", size = 3956366, upload-time = "2025-08-17T11:06:36.331Z" }, - { url = "https://files.pythonhosted.org/packages/db/de/b4fe4bfd0299de5fa1836e53f7b38d502b9bec21924e7939b1350ef261cc/blosc2-3.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e37cbabe3a30cf211ca19c329e0a91841f1e888654179c249a2809f87048c11f", size = 3424003, upload-time = "2025-08-17T11:06:37.735Z" }, - { url = "https://files.pythonhosted.org/packages/0d/27/83f648ffefd9e4b9057a97fbafb726d563abc850e4aaec1476b2752ba067/blosc2-3.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddfb8ceee263d3e607d32b415c9c0cecf35798b54155fda38810d5500a1e1717", size = 4313395, upload-time = "2025-08-17T11:06:39.49Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0a/bfa7bbfb77cb8a3d56a7fee7ffeba0596ae80d9c2d4dcc1a077c7898031e/blosc2-3.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:90886a4db7c0043be73f1eb02c810883cc9cdf88f0c54d0b024826ca04103cdb", size = 4447150, upload-time = "2025-08-17T11:06:40.959Z" }, - { url = "https://files.pythonhosted.org/packages/f3/a8/d080a11581071b7d9c13bd06e31ffefa0ea1c30937e972cf50a6ca67a422/blosc2-3.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:ab828e188f52ac21bd16cc03367d4a14ba9f1d52229771d087123690d77617da", size = 2286873, upload-time = "2025-08-17T11:06:42.952Z" }, - { url = "https://files.pythonhosted.org/packages/b6/53/13f49db9dbf7839de22b10d0192ac3eb650f11b212e57acaea7031fdf10f/blosc2-3.7.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1a9871e30a2516b6a318264aa6bf9230c9633b105ae832eaa5b9bc76ee80bbd7", size = 3974334, upload-time = "2025-08-17T11:06:44.464Z" }, - { url = "https://files.pythonhosted.org/packages/61/97/d3bdc5df22dae8f3afc604ce722465a684ac89d2e5f6b973f042fb597731/blosc2-3.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d18a9111103d392a42f0791497eecfbdc7d4ece4e0f8be281058d0a6061060d8", size = 3453513, upload-time = "2025-08-17T11:06:45.789Z" }, - { url = "https://files.pythonhosted.org/packages/cc/bf/d047ca8472d33bbb75c9d0b3884d6e92a4fbffe61148f8218313743f0ed5/blosc2-3.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7712d00e0c68fcbb3f59ac9ebe5cf35f98f57ff0a9cbdb6df618fa11f144d9f5", size = 4299984, upload-time = "2025-08-17T11:06:47.119Z" }, - { url = "https://files.pythonhosted.org/packages/88/d7/0a265a079d3c18d0b194e34a1f70dd7e49fb019d7f41ac74c035f1520665/blosc2-3.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5e1ec69d3efe54ac51171d89a725cb2109e3a4ad46d919d20db9fcea97d4d9eb", size = 4434793, upload-time = "2025-08-17T11:06:48.492Z" }, - { url = "https://files.pythonhosted.org/packages/ad/60/6c69bcfe74d8a3b97388f13b9e103c98fa7d3478378d18ba852ce3b98e28/blosc2-3.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0052f492478e7d09ca7874afb4c2e377b5dd690e022a60969155c4d2325d4ac9", size = 2333363, upload-time = "2025-08-17T11:06:50.5Z" }, + { url = "https://files.pythonhosted.org/packages/19/d3/b1b122c0a8c66e84204b811eabef297590cb60d171274d15c002b6af915e/blosc2-3.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:189a676efe2108b0ad3367ac60ae8932fc3e66216b64431e80af39ca7791ed9e", size = 3957716, upload-time = "2025-08-19T10:21:25.401Z" }, + { url = "https://files.pythonhosted.org/packages/59/6c/178461492297e1020d6b457d4fdb61f32953b9bf54f621b3e6c6766b2962/blosc2-3.7.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7601c0650822b55429f1022c55850f56771a15b2688a1b4208277f8f7be572dd", size = 3424350, upload-time = "2025-08-19T10:21:26.622Z" }, + { url = "https://files.pythonhosted.org/packages/2b/67/f4077aa38deb6536218e8473c9e5c9e11759146e1cad9f0b8e73ff5591e8/blosc2-3.7.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68fa544dc25dad8a9e32c7de903725360b51a12ceef8322a42d649fb07ce353b", size = 4310938, upload-time = "2025-08-19T10:21:28.142Z" }, + { url = "https://files.pythonhosted.org/packages/25/70/020cc09340973f361fcfbcfa2933fdb6301170edbe17215e24a5351d4c72/blosc2-3.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:78de4de35bb883fa627b2668265ff2f92586365c5a68da9f450115d5d1afa948", size = 4449950, upload-time = "2025-08-19T10:21:30.349Z" }, + { url = "https://files.pythonhosted.org/packages/88/a5/c9fcbd1fabf08f32e5d637487807e68a2d6c8985b1387283ab4122300377/blosc2-3.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e4de5a33cc5b5369da0d68ca84af148c5b9cc2e4ea70552e24f8b22fa14eb8c", size = 2243403, upload-time = "2025-08-19T10:21:31.529Z" }, + { url = "https://files.pythonhosted.org/packages/7b/28/99fa0d1cc43f75b83b83a4193bda323a0ef63384c6318bc5830c1635e0fa/blosc2-3.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f5271149bf13feec82dc6e196d933ec62b9cdb023cadc1f7d3de2ac15c0d5cd8", size = 3958164, upload-time = "2025-08-19T10:21:32.957Z" }, + { url = "https://files.pythonhosted.org/packages/d6/33/0fe8b67d185834f711177b2efa69d0faeafce5990e07f3c8f3fffdb1e159/blosc2-3.7.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8953b0be7f8e271e8db9464db22c11384ae64d0515b569da419f205d877f5b38", size = 3425837, upload-time = "2025-08-19T10:21:34.117Z" }, + { url = "https://files.pythonhosted.org/packages/ff/36/5961fe5c87f36e35e19db824e6d0d11785600b68df9835c4f74cb62ede62/blosc2-3.7.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3c8778fa3f22c530c4987794cd2e3bbf8c11749cf2fc6ff895fae4ea33964c31", size = 4315274, upload-time = "2025-08-19T10:21:35.19Z" }, + { url = "https://files.pythonhosted.org/packages/18/21/d382a8e211e720e0f2f6806809e5d1fca8f2424dc11fdd24c2f0ef3f1bf7/blosc2-3.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fdc2d0815082ea31f7afccf9c721d28fc0e3fc30e5a78e69bb60d61c6882dae9", size = 4449055, upload-time = "2025-08-19T10:21:36.366Z" }, + { url = "https://files.pythonhosted.org/packages/d2/75/de84468a706b8094d7810bf7bce1152c179cb03855adeaaaa0f475fd8446/blosc2-3.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:95d5077a6ce612e852f2d565bd0ed44e6f2ae959dc2e5d81d336528e5ce50e6f", size = 2288692, upload-time = "2025-08-19T10:21:38.057Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b9/0d95733a3e4d9106fd5a9949ea47258981ca8fcfc4f5d1636e9830bd54aa/blosc2-3.7.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d03dc32cedcf1230c6fa5e67184ff2fc9d899e235cef8be930a11111346bf586", size = 3976153, upload-time = "2025-08-19T10:21:39.207Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b9/5473042e7baf58c8e298fcba1ed2be221871d504d13cc54bee7f25ac8f11/blosc2-3.7.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3d7761a856d2984e24ec078db9a9648590c18cc7352be6fd6920a456d6d1c316", size = 3455367, upload-time = "2025-08-19T10:21:40.862Z" }, + { url = "https://files.pythonhosted.org/packages/da/1a/2d5c62d6b8e1c3a8ea9790a7e0ecc70aa21ddac61523eebd8ecec0f75c87/blosc2-3.7.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e56b671fbf78c706c523cdf60d6e6ef791df86a709aa6f3112efbef867c26602", size = 4301812, upload-time = "2025-08-19T10:21:42.292Z" }, + { url = "https://files.pythonhosted.org/packages/e7/54/8ce0ed4e4d01214d3b8642121577261cfb1faf055d84b8c1ea53a48a3ef5/blosc2-3.7.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13abd425da79d17f2c8359d948344238128f3d9f6f9621d002e9562afb8cddcd", size = 4436676, upload-time = "2025-08-19T10:21:43.478Z" }, + { url = "https://files.pythonhosted.org/packages/40/03/d14dee32c8f6fa70df585d276424d84bbb4f335db5dce6bf0d0cc13a4897/blosc2-3.7.2-cp314-cp314t-win_amd64.whl", hash = "sha256:40ef7de2282104caf8db0e501615bbabbb4249b82e167888b6b437ac656e33df", size = 2335189, upload-time = "2025-08-19T10:21:44.701Z" }, ] [[package]] @@ -627,17 +627,17 @@ wheels = [ [[package]] name = "hf-xet" -version = "1.1.7" +version = "1.1.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/0a/a0f56735940fde6dd627602fec9ab3bad23f66a272397560abd65aba416e/hf_xet-1.1.7.tar.gz", hash = "sha256:20cec8db4561338824a3b5f8c19774055b04a8df7fff0cb1ff2cb1a0c1607b80", size = 477719, upload-time = "2025-08-06T00:30:55.741Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/49/91010b59debc7c862a5fd426d343134dd9a68778dbe570234b6495a4e204/hf_xet-1.1.8.tar.gz", hash = "sha256:62a0043e441753bbc446dcb5a3fe40a4d03f5fb9f13589ef1df9ab19252beb53", size = 484065, upload-time = "2025-08-18T22:01:03.584Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/7c/8d7803995caf14e7d19a392a486a040f923e2cfeff824e9b800b92072f76/hf_xet-1.1.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:60dae4b44d520819e54e216a2505685248ec0adbdb2dd4848b17aa85a0375cde", size = 2761743, upload-time = "2025-08-06T00:30:50.634Z" }, - { url = "https://files.pythonhosted.org/packages/51/a3/fa5897099454aa287022a34a30e68dbff0e617760f774f8bd1db17f06bd4/hf_xet-1.1.7-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b109f4c11e01c057fc82004c9e51e6cdfe2cb230637644ade40c599739067b2e", size = 2624331, upload-time = "2025-08-06T00:30:49.212Z" }, - { url = "https://files.pythonhosted.org/packages/86/50/2446a132267e60b8a48b2e5835d6e24fd988000d0f5b9b15ebd6d64ef769/hf_xet-1.1.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6efaaf1a5a9fc3a501d3e71e88a6bfebc69ee3a716d0e713a931c8b8d920038f", size = 3183844, upload-time = "2025-08-06T00:30:47.582Z" }, - { url = "https://files.pythonhosted.org/packages/20/8f/ccc670616bb9beee867c6bb7139f7eab2b1370fe426503c25f5cbb27b148/hf_xet-1.1.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:751571540f9c1fbad9afcf222a5fb96daf2384bf821317b8bfb0c59d86078513", size = 3074209, upload-time = "2025-08-06T00:30:45.509Z" }, - { url = "https://files.pythonhosted.org/packages/21/0a/4c30e1eb77205565b854f5e4a82cf1f056214e4dc87f2918ebf83d47ae14/hf_xet-1.1.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:18b61bbae92d56ae731b92087c44efcac216071182c603fc535f8e29ec4b09b8", size = 3239602, upload-time = "2025-08-06T00:30:52.41Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1e/fc7e9baf14152662ef0b35fa52a6e889f770a7ed14ac239de3c829ecb47e/hf_xet-1.1.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:713f2bff61b252f8523739969f247aa354ad8e6d869b8281e174e2ea1bb8d604", size = 3348184, upload-time = "2025-08-06T00:30:54.105Z" }, - { url = "https://files.pythonhosted.org/packages/a3/73/e354eae84ceff117ec3560141224724794828927fcc013c5b449bf0b8745/hf_xet-1.1.7-cp37-abi3-win_amd64.whl", hash = "sha256:2e356da7d284479ae0f1dea3cf5a2f74fdf925d6dca84ac4341930d892c7cb34", size = 2820008, upload-time = "2025-08-06T00:30:57.056Z" }, + { url = "https://files.pythonhosted.org/packages/9c/91/5814db3a0d4a65fb6a87f0931ae28073b87f06307701fe66e7c41513bfb4/hf_xet-1.1.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3d5f82e533fc51c7daad0f9b655d9c7811b5308e5890236828bd1dd3ed8fea74", size = 2752357, upload-time = "2025-08-18T22:00:58.777Z" }, + { url = "https://files.pythonhosted.org/packages/70/72/ce898516e97341a7a9d450609e130e108643389110261eaee6deb1ba8545/hf_xet-1.1.8-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e2dba5896bca3ab61d0bef4f01a1647004de59640701b37e37eaa57087bbd9d", size = 2613142, upload-time = "2025-08-18T22:00:57.252Z" }, + { url = "https://files.pythonhosted.org/packages/b7/d6/13af5f916cef795ac2b5e4cc1de31f2e0e375f4475d50799915835f301c2/hf_xet-1.1.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfe5700bc729be3d33d4e9a9b5cc17a951bf8c7ada7ba0c9198a6ab2053b7453", size = 3175859, upload-time = "2025-08-18T22:00:55.978Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/34a193c9d1d72b7c3901b3b5153b1be9b2736b832692e1c3f167af537102/hf_xet-1.1.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:09e86514c3c4284ed8a57d6b0f3d089f9836a0af0a1ceb3c9dd664f1f3eaefef", size = 3074178, upload-time = "2025-08-18T22:00:54.147Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1b/de6817b4bf65385280252dff5c9cceeedfbcb27ddb93923639323c1034a4/hf_xet-1.1.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4a9b99ab721d385b83f4fc8ee4e0366b0b59dce03b5888a86029cc0ca634efbf", size = 3238122, upload-time = "2025-08-18T22:01:00.546Z" }, + { url = "https://files.pythonhosted.org/packages/b7/13/874c85c7ed519ec101deb654f06703d9e5e68d34416730f64c4755ada36a/hf_xet-1.1.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25b9d43333bbef39aeae1616789ec329c21401a7fe30969d538791076227b591", size = 3344325, upload-time = "2025-08-18T22:01:02.013Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/0aaf279f4f3dea58e99401b92c31c0f752924ba0e6c7d7bb07b1dbd7f35e/hf_xet-1.1.8-cp37-abi3-win_amd64.whl", hash = "sha256:4171f31d87b13da4af1ed86c98cf763292e4720c088b4957cf9d564f92904ca9", size = 2801689, upload-time = "2025-08-18T22:01:04.81Z" }, ] [[package]] @@ -1410,16 +1410,16 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.370.2" +version = "1.373.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "microdf-python" }, { name = "policyengine-core" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/51/d37cacb541a4fd0f4492820fad0a37767cecccf7c96999129e5799a03fc7/policyengine_us-1.370.2.tar.gz", hash = "sha256:4fee92a92848e842b91c74e7c7415200c9a585a362997667c809685e97ee9428", size = 7929001, upload-time = "2025-08-18T11:44:42.848Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/de/71af42a476b982946f51402c37857bbbb671cb6ff906d4b4b4f816f8d345/policyengine_us-1.373.1.tar.gz", hash = "sha256:5593c9391f3a4d941ab93ac0bac139ea702976a9b5e7a408afe7405311455eb1", size = 7932736, upload-time = "2025-08-19T21:32:09.569Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/96/ceec0e05541e2dce2b6d3e75a36da4d6ad757a6e03e19adc76d4417ae1ec/policyengine_us-1.370.2-py3-none-any.whl", hash = "sha256:5b4a5752d085bf85e791d5493c5c19a42793845f8b5f3020952f2df92707c429", size = 5820741, upload-time = "2025-08-18T11:44:38.938Z" }, + { url = "https://files.pythonhosted.org/packages/63/e6/7af16de20dbb836c85b7b91610aeafc575c81ca963332106d20ec17289d9/policyengine_us-1.373.1-py3-none-any.whl", hash = "sha256:967024f97ec36eb15aa17626f7f0a7b9c612472fe3ef99446c15bcd2d66619e0", size = 5826365, upload-time = "2025-08-19T21:32:05.387Z" }, ] [[package]] @@ -1745,7 +1745,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1753,9 +1753,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -1831,14 +1831,14 @@ wheels = [ [[package]] name = "ruamel-yaml" -version = "0.18.14" +version = "0.18.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ruamel-yaml-clib", marker = "python_full_version < '3.14' and platform_python_implementation == 'CPython'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/87/6da0df742a4684263261c253f00edd5829e6aca970fff69e75028cccc547/ruamel.yaml-0.18.14.tar.gz", hash = "sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7", size = 145511, upload-time = "2025-06-09T08:51:09.828Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/db/f3950f5e5031b618aae9f423a39bf81a55c148aecd15a34527898e752cf4/ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700", size = 146865, upload-time = "2025-08-19T11:15:10.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/6d/6fe4805235e193aad4aaf979160dd1f3c487c57d48b810c816e6e842171b/ruamel.yaml-0.18.14-py3-none-any.whl", hash = "sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2", size = 118570, upload-time = "2025-06-09T08:51:06.348Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/f2a0621f1781b76a38194acae72f01e37b1941470407345b6e8653ad7640/ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701", size = 119702, upload-time = "2025-08-19T11:15:07.696Z" }, ] [[package]] @@ -2055,7 +2055,7 @@ wheels = [ [[package]] name = "typer" -version = "0.16.0" +version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -2063,9 +2063,9 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, + { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, ] [[package]] diff --git a/projects/policyengine-api-tagger/Dockerfile b/projects/policyengine-api-tagger/Dockerfile index a7b12020..532e7f72 100644 --- a/projects/policyengine-api-tagger/Dockerfile +++ b/projects/policyengine-api-tagger/Dockerfile @@ -1,23 +1,32 @@ -FROM python:3.13-slim +# Multi-stage build inheriting from base +# Use explicit platform for consistency across builds +FROM --platform=linux/amd64 python:3.13-slim AS base + +# Install uv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -# Set environment variables -ENV ENVIRONMENT="production" \ - OT_SERVICE_NAME=policyengine_tagger_api \ - OT_SERVICE_INSTANCE_ID=instance +# Set common environment variables +ENV ENVIRONMENT="production" WORKDIR /app -# Copy LICENSE file to the root where it's expected +# Copy shared libraries and LICENSE COPY LICENSE ./LICENSE +COPY libs ./libs/ + +# Final stage +FROM base AS final + +# Service-specific environment +ENV OT_SERVICE_NAME=policyengine_tagger_api \ + OT_SERVICE_INSTANCE_ID=instance -# Copy the entire project structure for dependencies -COPY libs/policyengine-fastapi ./libs/policyengine-fastapi/ +# Copy service-specific code COPY projects/policyengine-api-tagger ./projects/policyengine-api-tagger/ WORKDIR /app/projects/policyengine-api-tagger -# Install dependencies using uv +# Install dependencies RUN uv sync --frozen --no-dev EXPOSE 8080 diff --git a/projects/policyengine-api-tagger/Makefile b/projects/policyengine-api-tagger/Makefile deleted file mode 100644 index cbb21cbd..00000000 --- a/projects/policyengine-api-tagger/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ./makefile.env -include ../../server_common.local.mk diff --git a/projects/policyengine-api-tagger/Makefile.deploy b/projects/policyengine-api-tagger/Makefile.deploy deleted file mode 100644 index 551ba839..00000000 --- a/projects/policyengine-api-tagger/Makefile.deploy +++ /dev/null @@ -1,2 +0,0 @@ -include makefile.env -include ../../server_common.deploy.mk diff --git a/projects/policyengine-api-tagger/makefile.env b/projects/policyengine-api-tagger/makefile.env deleted file mode 100644 index 138d54ff..00000000 --- a/projects/policyengine-api-tagger/makefile.env +++ /dev/null @@ -1,3 +0,0 @@ -SERVICE_NAME=policyengine-api-tagger -MODULE_NAME=policyengine_api_tagger.main -DEV_PORT=8082 diff --git a/projects/policyengine-api-tagger/pyproject.toml b/projects/policyengine-api-tagger/pyproject.toml index 64af2959..53bafeeb 100644 --- a/projects/policyengine-api-tagger/pyproject.toml +++ b/projects/policyengine-api-tagger/pyproject.toml @@ -30,7 +30,7 @@ build = [ "pyright>=1.1.401", "black>=25.1.0",] pythonpath = [ "src", ] -addopts = "--cov=policyengine_api_tagger --cov-report=term-missing --cov-fail-under=60" +addopts = "--cov=policyengine_api_tagger --cov-report=term-missing" [tool.uv.sources] policyengine-fastapi = { path = "../../libs/policyengine-fastapi", editable = true } diff --git a/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/cloudrun_client.py b/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/cloudrun_client.py index 07fb54c3..62746aa5 100644 --- a/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/cloudrun_client.py +++ b/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/cloudrun_client.py @@ -11,7 +11,6 @@ class CloudrunClient: - async def tag_revision( self, cloudrun_service_name: str, revision_name: str, tag: str ) -> str: diff --git a/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/revision_tagger.py b/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/revision_tagger.py index 77287aee..ffd3d586 100644 --- a/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/revision_tagger.py +++ b/projects/policyengine-api-tagger/src/policyengine_api_tagger/api/revision_tagger.py @@ -78,7 +78,7 @@ async def tag(self, country: str, model_version: str) -> str | None: revision_name = revision_path.split("/")[-1] cloudrun_service_name = revision_path.rsplit("/revisions/", 1)[0] - tag_string = f"country-{country}-model-{model_version.replace('.','-')}" + tag_string = f"country-{country}-model-{model_version.replace('.', '-')}" log.info( f"Getting tagged url for service {cloudrun_service_name}, revision {revision_name}, tag {tag_string}" diff --git a/projects/policyengine-api-tagger/src/policyengine_api_tagger/main.py b/projects/policyengine-api-tagger/src/policyengine_api_tagger/main.py index dcd422b4..acc493b7 100644 --- a/projects/policyengine-api-tagger/src/policyengine_api_tagger/main.py +++ b/projects/policyengine-api-tagger/src/policyengine_api_tagger/main.py @@ -1,17 +1,17 @@ from contextlib import asynccontextmanager from typing import Any from fastapi import FastAPI -from policyengine_api.fastapi import ping -from policyengine_api.fastapi.health import ( +from policyengine_fastapi import ping +from policyengine_fastapi.health import ( HealthRegistry, HealthSystemReporter, ) -from policyengine_api.fastapi.exit import exit +from policyengine_fastapi.exit import exit from .api.revision_tagger import RevisionTagger from .api.routes import add_all_routes from .api.settings import get_settings, Environment -from policyengine_api.fastapi.opentelemetry import ( +from policyengine_fastapi.opentelemetry import ( GCPLoggingInstrumentor, FastAPIEnhancedInstrumenter, export_ot_to_console, @@ -61,7 +61,7 @@ } ) -match (get_settings().environment): +match get_settings().environment: case Environment.DESKTOP: pass # export_ot_to_console(resource) case Environment.PRODUCTION: diff --git a/projects/policyengine-api-tagger/uv.lock b/projects/policyengine-api-tagger/uv.lock index 3606218b..aaba5d9d 100644 --- a/projects/policyengine-api-tagger/uv.lock +++ b/projects/policyengine-api-tagger/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13" [[package]] @@ -1168,7 +1168,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1176,9 +1176,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -1331,7 +1331,7 @@ wheels = [ [[package]] name = "typer" -version = "0.16.0" +version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1339,9 +1339,9 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, + { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, ] [[package]] diff --git a/projects/policyengine-apis-integ/Makefile b/projects/policyengine-apis-integ/Makefile deleted file mode 100644 index a4a4e7bf..00000000 --- a/projects/policyengine-apis-integ/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../../common.mk -US_COUNTRY_PACKAGE_VERSION := $(shell ../../projects/policyengine-api-simulation/dump_package_version.sh policyengine-us) -UK_COUNTRY_PACKAGE_VERSION := $(shell ../../projects/policyengine-api-simulation/dump_package_version.sh policyengine-uk) - -test: integ-test - echo "Skipping default test target in favor of integ-test" - -integ-test: - echo "Running integration tests" - $(if $(FULL_API_ACCESS_TOKEN),FULL_INTEG_TEST_ACCESS_TOKEN='$(FULL_API_ACCESS_TOKEN)') \ - $(if $(SIMULATION_API_ACCESS_TOKEN),SIMULATION_INTEG_TEST_ACCESS_TOKEN='$(SIMULATION_API_ACCESS_TOKEN)') \ - $(if $(FULL_API_URL),FULL_INTEG_TEST_BASE_URL='$(FULL_API_URL)') \ - $(if $(SIMULATION_API_URL),SIMULATION_INTEG_TEST_BASE_URL='$(SIMULATION_API_URL)') \ - $(if $(TF_VAR_project_id),WORKFLOW_INTEG_TEST_PROJECT_ID='$(TF_VAR_project_id)') \ - $(if $(PROJECT_ID),WORKFLOW_INTEG_TEST_PROJECT_ID='$(PROJECT_ID)') \ - WORKFLOW_INTEG_TEST_US_MODEL_VERSION='$(US_COUNTRY_PACKAGE_VERSION)' \ - pytest -n auto diff --git a/projects/policyengine-apis-integ/pyproject.toml b/projects/policyengine-apis-integ/pyproject.toml index f4cbb619..bea01080 100644 --- a/projects/policyengine-apis-integ/pyproject.toml +++ b/projects/policyengine-apis-integ/pyproject.toml @@ -24,6 +24,9 @@ pythonpath = [ "src", ] testpaths = ["tests"] +markers = [ + "requires_gcp: mark test as requiring GCP credentials and workflow access", +] [tool.uv.sources] policyengine_api_full_client = { path = "../policyengine-api-full/artifacts/clients/python" } diff --git a/projects/policyengine-apis-integ/tests/full/conftest.py b/projects/policyengine-apis-integ/tests/full/conftest.py index 04d0d70f..3f88c4bf 100644 --- a/projects/policyengine-apis-integ/tests/full/conftest.py +++ b/projects/policyengine-apis-integ/tests/full/conftest.py @@ -5,7 +5,7 @@ class Settings(BaseSettings): - base_url: str = "http://localhost:8080" + base_url: str = "http://localhost:8081" access_token: str | None = None timeout_in_millis: int = 2_000 diff --git a/projects/policyengine-apis-integ/tests/simulation/conftest.py b/projects/policyengine-apis-integ/tests/simulation/conftest.py index 1bfb2afa..0c28ea6e 100644 --- a/projects/policyengine-apis-integ/tests/simulation/conftest.py +++ b/projects/policyengine-apis-integ/tests/simulation/conftest.py @@ -5,7 +5,7 @@ class Settings(BaseSettings): - base_url: str = "http://localhost:8081" + base_url: str = "http://localhost:8082" access_token: str | None = None timeout_in_millis: int = 120_000 diff --git a/projects/policyengine-apis-integ/tests/simulation_workflow/conftest.py b/projects/policyengine-apis-integ/tests/simulation_workflow/conftest.py index 3202b88e..676effa2 100644 --- a/projects/policyengine-apis-integ/tests/simulation_workflow/conftest.py +++ b/projects/policyengine-apis-integ/tests/simulation_workflow/conftest.py @@ -1,6 +1,7 @@ from pydantic_settings import BaseSettings, SettingsConfigDict import pytest from .simplified_workflow_client import SimplifiedWorkflowClient +import os class Settings(BaseSettings): @@ -15,6 +16,15 @@ class Settings(BaseSettings): settings = Settings() +# Skip all workflow tests if we don't have proper GCP configuration +pytestmark = pytest.mark.skipif( + settings.project_id == "UNKNOWN_PROJECT_ID" or + settings.us_model_version == "UNKNOWN_US_MODEL_VERSION" or + not os.getenv("GOOGLE_APPLICATION_CREDENTIALS", ""), + reason="Workflow tests require GCP credentials and configuration" +) + + @pytest.fixture() def us_model_version() -> str: return settings.us_model_version diff --git a/projects/policyengine-apis-integ/tests/simulation_workflow/test_calculate.py b/projects/policyengine-apis-integ/tests/simulation_workflow/test_calculate.py index 50c7e483..3ed9c143 100644 --- a/projects/policyengine-apis-integ/tests/simulation_workflow/test_calculate.py +++ b/projects/policyengine-apis-integ/tests/simulation_workflow/test_calculate.py @@ -1,7 +1,9 @@ +import pytest from .simplified_workflow_client import SimplifiedWorkflowClient from google.cloud.workflows.executions_v1.types import executions +@pytest.mark.requires_gcp def test_calculate_default_model(client: SimplifiedWorkflowClient): execution = client.execute( argument={ @@ -19,6 +21,7 @@ def test_calculate_default_model(client: SimplifiedWorkflowClient): assert execution.state == executions.Execution.State.SUCCEEDED +@pytest.mark.requires_gcp def test_calculate_specific_model( client: SimplifiedWorkflowClient, us_model_version: str ): diff --git a/projects/policyengine-apis-integ/uv.lock b/projects/policyengine-apis-integ/uv.lock index 34711f69..98b04f87 100644 --- a/projects/policyengine-apis-integ/uv.lock +++ b/projects/policyengine-apis-integ/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13, <4.0" [[package]] @@ -605,7 +605,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -613,9 +613,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] diff --git a/projects/policyengine-household-api/.dockerignore b/projects/policyengine-household-api/.dockerignore deleted file mode 100644 index 9af6cc84..00000000 --- a/projects/policyengine-household-api/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -.git -.venv -__pycache__/ -build/**/build diff --git a/projects/policyengine-household-api/.gcloudignore b/projects/policyengine-household-api/.gcloudignore deleted file mode 100644 index 429d5e71..00000000 --- a/projects/policyengine-household-api/.gcloudignore +++ /dev/null @@ -1,4 +0,0 @@ -.venv -.git -terraform -__pycache__ diff --git a/projects/policyengine-household-api/Dockerfile b/projects/policyengine-household-api/Dockerfile deleted file mode 100644 index fc00cfa9..00000000 --- a/projects/policyengine-household-api/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM python:3.13-slim - -# Install uv -RUN pip install uv - -# Set environment variables -ENV ENVIRONMENT="desktop" \ - OT_SERVICE_NAME=policyengine_household_api \ - OT_SERVICE_INSTANCE_ID=instance - -WORKDIR /app - -# Copy LICENSE file to the root where it's expected -COPY LICENSE ./LICENSE - -# Copy the entire project structure for dependencies -COPY libs/policyengine-api ./libs/policyengine-api/ -COPY projects/policyengine-household-api ./projects/policyengine-household-api/ - -WORKDIR /app/projects/policyengine-household-api - -# Install dependencies using uv -RUN uv sync --frozen --no-dev - -EXPOSE 8080 - -# Run with uvicorn - add src to PYTHONPATH and run -ENV PYTHONPATH=/app/projects/policyengine-household-api/src -CMD ["uv", "run", "uvicorn", "policyengine_household_api.main:app", "--host", "0.0.0.0", "--port", "8080"] \ No newline at end of file diff --git a/projects/policyengine-household-api/Makefile b/projects/policyengine-household-api/Makefile deleted file mode 100644 index d552a70e..00000000 --- a/projects/policyengine-household-api/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ./makefile.env -include ../../server_common.local.mk - -test: - echo "Skipping tests..." diff --git a/projects/policyengine-household-api/Makefile.deploy b/projects/policyengine-household-api/Makefile.deploy deleted file mode 100644 index 551ba839..00000000 --- a/projects/policyengine-household-api/Makefile.deploy +++ /dev/null @@ -1,2 +0,0 @@ -include makefile.env -include ../../server_common.deploy.mk diff --git a/projects/policyengine-household-api/README.md b/projects/policyengine-household-api/README.md deleted file mode 100644 index 343fab97..00000000 --- a/projects/policyengine-household-api/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# policyengine-household-api - -PolicyEngine Household API service. \ No newline at end of file diff --git a/projects/policyengine-household-api/makefile.env b/projects/policyengine-household-api/makefile.env deleted file mode 100644 index 5a65e084..00000000 --- a/projects/policyengine-household-api/makefile.env +++ /dev/null @@ -1,3 +0,0 @@ -SERVICE_NAME=policyengine-api-household -MODULE_NAME=policyengine_api_household.main -DEV_PORT=8083 diff --git a/projects/policyengine-household-api/pyproject.toml b/projects/policyengine-household-api/pyproject.toml deleted file mode 100644 index eed45970..00000000 --- a/projects/policyengine-household-api/pyproject.toml +++ /dev/null @@ -1,37 +0,0 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] -name = "policyengine_household_api" -version = "0.1.0" -readme = "README.md" -requires-python = ">=3.13" -dependencies = [ - "opentelemetry-instrumentation-sqlalchemy (>=0.51b0,<0.52)", - "pydantic-settings (>=2.7.1,<3.0.0)", - "opentelemetry-instrumentation-fastapi (>=0.51b0,<0.52)", - "fastapi (>=0.115.8, <0.116.0)", - "policyengine-fastapi", - "policyengine-uk (>=2.19.1)", - "policyengine-us (>=1.202.2,<1.338.0)", - "policyengine-il (>=0.1.0)", - "policyengine-ng (>=0.5.1)", - "numpy (>=2.0.0,<3.0.0)" -] - -[tool.hatch.build.targets.wheel] -packages = ["src/policyengine_household_api"] - -[project.optional-dependencies] -test = [ "pytest>=8.3.4", "pytest-asyncio>=0.25.3", "pytest-cov>=6.1.1",] -build = [ "pyright>=1.1.401", "black>=25.1.0",] - -[tool.pytest.ini_options] -pythonpath = [ - "src", -] -testpaths = ["tests"] - -[tool.uv.sources] -policyengine-fastapi = { path = "../../libs/policyengine-fastapi", editable = true } diff --git a/projects/policyengine-household-api/src/policyengine_household_api/main.py b/projects/policyengine-household-api/src/policyengine_household_api/main.py deleted file mode 100644 index eef7e20f..00000000 --- a/projects/policyengine-household-api/src/policyengine_household_api/main.py +++ /dev/null @@ -1,60 +0,0 @@ -from fastapi import FastAPI -from policyengine_household_api.settings import get_settings, Environment -from policyengine_api.fastapi.opentelemetry import ( - GCPLoggingInstrumentor, - FastAPIEnhancedInstrumenter, - export_ot_to_console, - export_ot_to_gcp, -) -from opentelemetry.sdk.resources import ( - SERVICE_NAME, - SERVICE_INSTANCE_ID, - Resource, -) -from policyengine_api.api.routers import ( - calculate, - metadata, -) -from policyengine_api.api import initialize -import logging - -""" -specific example instantiation of the app configured by a .env file -* in all environments we use sqlite -* on desktop we print opentelemetry instrumentation to the console. -* in "production" we use GCP trace/metrics bindings. -""" - -logger = logging.getLogger(__name__) - -app = FastAPI() - -app.include_router(calculate.router) -app.include_router(metadata.router) - -# attach the api defined in the app package -initialize( - app=app, - engine=None, # type: ignore - jwt_issuer=get_settings().jwt_issuer, - jwt_audience=get_settings().jwt_audience, -) - -# configure tracing and metrics -GCPLoggingInstrumentor().instrument() -FastAPIEnhancedInstrumenter().instrument(app) - -resource = Resource.create( - attributes={ - SERVICE_NAME: get_settings().ot_service_name, - SERVICE_INSTANCE_ID: get_settings().ot_service_instance_id, - } -) - -match (get_settings().environment): - case Environment.DESKTOP: - pass # export_ot_to_console(resource) - case Environment.PRODUCTION: - export_ot_to_gcp(resource) - case value: - raise Exception(f"Forgot to handle environment value {value}") diff --git a/projects/policyengine-household-api/src/policyengine_household_api/settings.py b/projects/policyengine-household-api/src/policyengine_household_api/settings.py deleted file mode 100644 index e8f8bc8d..00000000 --- a/projects/policyengine-household-api/src/policyengine_household_api/settings.py +++ /dev/null @@ -1,36 +0,0 @@ -from enum import Enum -from functools import lru_cache -from pydantic_settings import BaseSettings, SettingsConfigDict - - -class Environment(Enum): - DESKTOP = "desktop" - PRODUCTION = "production" - - -class AppSettings(BaseSettings): - environment: Environment = Environment.DESKTOP - - jwt_issuer: str = "https://your_issuer/" - """ - The issuer that must sign any JWT bearer token before the API with accept it as valid - """ - jwt_audience: str = "https://your_api/" - """ - The audience that any JWT bearer token must include in order to be accepted by the API - """ - ot_service_name: str = "YOUR_OT_SERVICE_NAME" - """ - service name used by opentelemetry when reporting trace information - """ - ot_service_instance_id: str = "YOUR_OT_INSTANCE_ID" - """ - instance id used by opentelemetry when reporting trace information - """ - - model_config = SettingsConfigDict(env_file=".env") - - -@lru_cache -def get_settings(): - return AppSettings() diff --git a/projects/policyengine-household-api/uv.lock b/projects/policyengine-household-api/uv.lock deleted file mode 100644 index a167fa74..00000000 --- a/projects/policyengine-household-api/uv.lock +++ /dev/null @@ -1,2022 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.13" - -[[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, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, -] - -[[package]] -name = "asgiref" -version = "3.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/61/0aa957eec22ff70b830b22ff91f825e70e1ef732c06666a805730f28b36b/asgiref-3.9.1.tar.gz", hash = "sha256:a5ab6582236218e5ef1648f242fd9f10626cfd4de8dc377db215d5d5098e3142", size = 36870, upload-time = "2025-07-08T09:07:43.344Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/3c/0464dcada90d5da0e71018c04a140ad6349558afb30b3051b4264cc5b965/asgiref-3.9.1-py3-none-any.whl", hash = "sha256:f3bba7092a48005b5f5bacd747d36ee4a5a61f4a269a6df590b43144355ebd2c", size = 23790, upload-time = "2025-07-08T09:07:41.548Z" }, -] - -[[package]] -name = "asttokens" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, -] - -[[package]] -name = "black" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673, upload-time = "2025-01-29T05:37:20.574Z" }, - { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190, upload-time = "2025-01-29T05:37:22.106Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926, upload-time = "2025-01-29T04:18:58.564Z" }, - { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613, upload-time = "2025-01-29T04:19:27.63Z" }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, -] - -[[package]] -name = "cachetools" -version = "5.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, -] - -[[package]] -name = "certifi" -version = "2025.8.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, - { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, - { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, - { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, - { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, - { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, - { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, - { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, - { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, - { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, - { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, - { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, - { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, - { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, - { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, - { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[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, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "coverage" -version = "7.10.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/4e/08b493f1f1d8a5182df0044acc970799b58a8d289608e0d891a03e9d269a/coverage-7.10.4.tar.gz", hash = "sha256:25f5130af6c8e7297fd14634955ba9e1697f47143f289e2a23284177c0061d27", size = 823798, upload-time = "2025-08-17T00:26:43.314Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/b0/4a3662de81f2ed792a4e425d59c4ae50d8dd1d844de252838c200beed65a/coverage-7.10.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b8e1d2015d5dfdbf964ecef12944c0c8c55b885bb5c0467ae8ef55e0e151233", size = 216735, upload-time = "2025-08-17T00:25:08.617Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e8/e2dcffea01921bfffc6170fb4406cffb763a3b43a047bbd7923566708193/coverage-7.10.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25735c299439018d66eb2dccf54f625aceb78645687a05f9f848f6e6c751e169", size = 216982, upload-time = "2025-08-17T00:25:10.384Z" }, - { url = "https://files.pythonhosted.org/packages/9d/59/cc89bb6ac869704d2781c2f5f7957d07097c77da0e8fdd4fd50dbf2ac9c0/coverage-7.10.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:715c06cb5eceac4d9b7cdf783ce04aa495f6aff657543fea75c30215b28ddb74", size = 247981, upload-time = "2025-08-17T00:25:11.854Z" }, - { url = "https://files.pythonhosted.org/packages/aa/23/3da089aa177ceaf0d3f96754ebc1318597822e6387560914cc480086e730/coverage-7.10.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e017ac69fac9aacd7df6dc464c05833e834dc5b00c914d7af9a5249fcccf07ef", size = 250584, upload-time = "2025-08-17T00:25:13.483Z" }, - { url = "https://files.pythonhosted.org/packages/ad/82/e8693c368535b4e5fad05252a366a1794d481c79ae0333ed943472fd778d/coverage-7.10.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bad180cc40b3fccb0f0e8c702d781492654ac2580d468e3ffc8065e38c6c2408", size = 251856, upload-time = "2025-08-17T00:25:15.27Z" }, - { url = "https://files.pythonhosted.org/packages/56/19/8b9cb13292e602fa4135b10a26ac4ce169a7fc7c285ff08bedd42ff6acca/coverage-7.10.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:becbdcd14f685fada010a5f792bf0895675ecf7481304fe159f0cd3f289550bd", size = 250015, upload-time = "2025-08-17T00:25:16.759Z" }, - { url = "https://files.pythonhosted.org/packages/10/e7/e5903990ce089527cf1c4f88b702985bd65c61ac245923f1ff1257dbcc02/coverage-7.10.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b485ca21e16a76f68060911f97ebbe3e0d891da1dbbce6af7ca1ab3f98b9097", size = 247908, upload-time = "2025-08-17T00:25:18.232Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c9/7d464f116df1df7fe340669af1ddbe1a371fc60f3082ff3dc837c4f1f2ab/coverage-7.10.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6c1d098ccfe8e1e0a1ed9a0249138899948afd2978cbf48eb1cc3fcd38469690", size = 249525, upload-time = "2025-08-17T00:25:20.141Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/722e0cdbf6c19e7235c2020837d4e00f3b07820fd012201a983238cc3a30/coverage-7.10.4-cp313-cp313-win32.whl", hash = "sha256:8630f8af2ca84b5c367c3df907b1706621abe06d6929f5045fd628968d421e6e", size = 219173, upload-time = "2025-08-17T00:25:21.56Z" }, - { url = "https://files.pythonhosted.org/packages/97/7e/aa70366f8275955cd51fa1ed52a521c7fcebcc0fc279f53c8c1ee6006dfe/coverage-7.10.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68835d31c421736be367d32f179e14ca932978293fe1b4c7a6a49b555dff5b2", size = 219969, upload-time = "2025-08-17T00:25:23.501Z" }, - { url = "https://files.pythonhosted.org/packages/ac/96/c39d92d5aad8fec28d4606556bfc92b6fee0ab51e4a548d9b49fb15a777c/coverage-7.10.4-cp313-cp313-win_arm64.whl", hash = "sha256:6eaa61ff6724ca7ebc5326d1fae062d85e19b38dd922d50903702e6078370ae7", size = 218601, upload-time = "2025-08-17T00:25:25.295Z" }, - { url = "https://files.pythonhosted.org/packages/79/13/34d549a6177bd80fa5db758cb6fd3057b7ad9296d8707d4ab7f480b0135f/coverage-7.10.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:702978108876bfb3d997604930b05fe769462cc3000150b0e607b7b444f2fd84", size = 217445, upload-time = "2025-08-17T00:25:27.129Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c0/433da866359bf39bf595f46d134ff2d6b4293aeea7f3328b6898733b0633/coverage-7.10.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e8f978e8c5521d9c8f2086ac60d931d583fab0a16f382f6eb89453fe998e2484", size = 217676, upload-time = "2025-08-17T00:25:28.641Z" }, - { url = "https://files.pythonhosted.org/packages/7e/d7/2b99aa8737f7801fd95222c79a4ebc8c5dd4460d4bed7ef26b17a60c8d74/coverage-7.10.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:df0ac2ccfd19351411c45e43ab60932b74472e4648b0a9edf6a3b58846e246a9", size = 259002, upload-time = "2025-08-17T00:25:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/08/cf/86432b69d57debaef5abf19aae661ba8f4fcd2882fa762e14added4bd334/coverage-7.10.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73a0d1aaaa3796179f336448e1576a3de6fc95ff4f07c2d7251d4caf5d18cf8d", size = 261178, upload-time = "2025-08-17T00:25:31.517Z" }, - { url = "https://files.pythonhosted.org/packages/23/78/85176593f4aa6e869cbed7a8098da3448a50e3fac5cb2ecba57729a5220d/coverage-7.10.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:873da6d0ed6b3ffc0bc01f2c7e3ad7e2023751c0d8d86c26fe7322c314b031dc", size = 263402, upload-time = "2025-08-17T00:25:33.339Z" }, - { url = "https://files.pythonhosted.org/packages/88/1d/57a27b6789b79abcac0cc5805b31320d7a97fa20f728a6a7c562db9a3733/coverage-7.10.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c6446c75b0e7dda5daa876a1c87b480b2b52affb972fedd6c22edf1aaf2e00ec", size = 260957, upload-time = "2025-08-17T00:25:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/fa/e5/3e5ddfd42835c6def6cd5b2bdb3348da2e34c08d9c1211e91a49e9fd709d/coverage-7.10.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6e73933e296634e520390c44758d553d3b573b321608118363e52113790633b9", size = 258718, upload-time = "2025-08-17T00:25:36.259Z" }, - { url = "https://files.pythonhosted.org/packages/1a/0b/d364f0f7ef111615dc4e05a6ed02cac7b6f2ac169884aa57faeae9eb5fa0/coverage-7.10.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52073d4b08d2cb571234c8a71eb32af3c6923149cf644a51d5957ac128cf6aa4", size = 259848, upload-time = "2025-08-17T00:25:37.754Z" }, - { url = "https://files.pythonhosted.org/packages/10/c6/bbea60a3b309621162e53faf7fac740daaf083048ea22077418e1ecaba3f/coverage-7.10.4-cp313-cp313t-win32.whl", hash = "sha256:e24afb178f21f9ceb1aefbc73eb524769aa9b504a42b26857243f881af56880c", size = 219833, upload-time = "2025-08-17T00:25:39.252Z" }, - { url = "https://files.pythonhosted.org/packages/44/a5/f9f080d49cfb117ddffe672f21eab41bd23a46179a907820743afac7c021/coverage-7.10.4-cp313-cp313t-win_amd64.whl", hash = "sha256:be04507ff1ad206f4be3d156a674e3fb84bbb751ea1b23b142979ac9eebaa15f", size = 220897, upload-time = "2025-08-17T00:25:40.772Z" }, - { url = "https://files.pythonhosted.org/packages/46/89/49a3fc784fa73d707f603e586d84a18c2e7796707044e9d73d13260930b7/coverage-7.10.4-cp313-cp313t-win_arm64.whl", hash = "sha256:f3e3ff3f69d02b5dad67a6eac68cc9c71ae343b6328aae96e914f9f2f23a22e2", size = 219160, upload-time = "2025-08-17T00:25:42.229Z" }, - { url = "https://files.pythonhosted.org/packages/b5/22/525f84b4cbcff66024d29f6909d7ecde97223f998116d3677cfba0d115b5/coverage-7.10.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a59fe0af7dd7211ba595cf7e2867458381f7e5d7b4cffe46274e0b2f5b9f4eb4", size = 216717, upload-time = "2025-08-17T00:25:43.875Z" }, - { url = "https://files.pythonhosted.org/packages/a6/58/213577f77efe44333a416d4bcb251471e7f64b19b5886bb515561b5ce389/coverage-7.10.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3a6c35c5b70f569ee38dc3350cd14fdd0347a8b389a18bb37538cc43e6f730e6", size = 216994, upload-time = "2025-08-17T00:25:45.405Z" }, - { url = "https://files.pythonhosted.org/packages/17/85/34ac02d0985a09472f41b609a1d7babc32df87c726c7612dc93d30679b5a/coverage-7.10.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:acb7baf49f513554c4af6ef8e2bd6e8ac74e6ea0c7386df8b3eb586d82ccccc4", size = 248038, upload-time = "2025-08-17T00:25:46.981Z" }, - { url = "https://files.pythonhosted.org/packages/47/4f/2140305ec93642fdaf988f139813629cbb6d8efa661b30a04b6f7c67c31e/coverage-7.10.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a89afecec1ed12ac13ed203238b560cbfad3522bae37d91c102e690b8b1dc46c", size = 250575, upload-time = "2025-08-17T00:25:48.613Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b5/41b5784180b82a083c76aeba8f2c72ea1cb789e5382157b7dc852832aea2/coverage-7.10.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:480442727f464407d8ade6e677b7f21f3b96a9838ab541b9a28ce9e44123c14e", size = 251927, upload-time = "2025-08-17T00:25:50.881Z" }, - { url = "https://files.pythonhosted.org/packages/78/ca/c1dd063e50b71f5aea2ebb27a1c404e7b5ecf5714c8b5301f20e4e8831ac/coverage-7.10.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a89bf193707f4a17f1ed461504031074d87f035153239f16ce86dfb8f8c7ac76", size = 249930, upload-time = "2025-08-17T00:25:52.422Z" }, - { url = "https://files.pythonhosted.org/packages/8d/66/d8907408612ffee100d731798e6090aedb3ba766ecf929df296c1a7ee4fb/coverage-7.10.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:3ddd912c2fc440f0fb3229e764feec85669d5d80a988ff1b336a27d73f63c818", size = 247862, upload-time = "2025-08-17T00:25:54.316Z" }, - { url = "https://files.pythonhosted.org/packages/29/db/53cd8ec8b1c9c52d8e22a25434785bfc2d1e70c0cfb4d278a1326c87f741/coverage-7.10.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a538944ee3a42265e61c7298aeba9ea43f31c01271cf028f437a7b4075592cf", size = 249360, upload-time = "2025-08-17T00:25:55.833Z" }, - { url = "https://files.pythonhosted.org/packages/4f/75/5ec0a28ae4a0804124ea5a5becd2b0fa3adf30967ac656711fb5cdf67c60/coverage-7.10.4-cp314-cp314-win32.whl", hash = "sha256:fd2e6002be1c62476eb862b8514b1ba7e7684c50165f2a8d389e77da6c9a2ebd", size = 219449, upload-time = "2025-08-17T00:25:57.984Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ab/66e2ee085ec60672bf5250f11101ad8143b81f24989e8c0e575d16bb1e53/coverage-7.10.4-cp314-cp314-win_amd64.whl", hash = "sha256:ec113277f2b5cf188d95fb66a65c7431f2b9192ee7e6ec9b72b30bbfb53c244a", size = 220246, upload-time = "2025-08-17T00:25:59.868Z" }, - { url = "https://files.pythonhosted.org/packages/37/3b/00b448d385f149143190846217797d730b973c3c0ec2045a7e0f5db3a7d0/coverage-7.10.4-cp314-cp314-win_arm64.whl", hash = "sha256:9744954bfd387796c6a091b50d55ca7cac3d08767795b5eec69ad0f7dbf12d38", size = 218825, upload-time = "2025-08-17T00:26:01.44Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/55e20d3d1ce00b513efb6fd35f13899e1c6d4f76c6cbcc9851c7227cd469/coverage-7.10.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5af4829904dda6aabb54a23879f0f4412094ba9ef153aaa464e3c1b1c9bc98e6", size = 217462, upload-time = "2025-08-17T00:26:03.014Z" }, - { url = "https://files.pythonhosted.org/packages/47/b3/aab1260df5876f5921e2c57519e73a6f6eeacc0ae451e109d44ee747563e/coverage-7.10.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7bba5ed85e034831fac761ae506c0644d24fd5594727e174b5a73aff343a7508", size = 217675, upload-time = "2025-08-17T00:26:04.606Z" }, - { url = "https://files.pythonhosted.org/packages/67/23/1cfe2aa50c7026180989f0bfc242168ac7c8399ccc66eb816b171e0ab05e/coverage-7.10.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d57d555b0719834b55ad35045de6cc80fc2b28e05adb6b03c98479f9553b387f", size = 259176, upload-time = "2025-08-17T00:26:06.159Z" }, - { url = "https://files.pythonhosted.org/packages/9d/72/5882b6aeed3f9de7fc4049874fd7d24213bf1d06882f5c754c8a682606ec/coverage-7.10.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ba62c51a72048bb1ea72db265e6bd8beaabf9809cd2125bbb5306c6ce105f214", size = 261341, upload-time = "2025-08-17T00:26:08.137Z" }, - { url = "https://files.pythonhosted.org/packages/1b/70/a0c76e3087596ae155f8e71a49c2c534c58b92aeacaf4d9d0cbbf2dde53b/coverage-7.10.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0acf0c62a6095f07e9db4ec365cc58c0ef5babb757e54745a1aa2ea2a2564af1", size = 263600, upload-time = "2025-08-17T00:26:11.045Z" }, - { url = "https://files.pythonhosted.org/packages/cb/5f/27e4cd4505b9a3c05257fb7fc509acbc778c830c450cb4ace00bf2b7bda7/coverage-7.10.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1033bf0f763f5cf49ffe6594314b11027dcc1073ac590b415ea93463466deec", size = 261036, upload-time = "2025-08-17T00:26:12.693Z" }, - { url = "https://files.pythonhosted.org/packages/02/d6/cf2ae3a7f90ab226ea765a104c4e76c5126f73c93a92eaea41e1dc6a1892/coverage-7.10.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:92c29eff894832b6a40da1789b1f252305af921750b03ee4535919db9179453d", size = 258794, upload-time = "2025-08-17T00:26:14.261Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b1/39f222eab0d78aa2001cdb7852aa1140bba632db23a5cfd832218b496d6c/coverage-7.10.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:822c4c830989c2093527e92acd97be4638a44eb042b1bdc0e7a278d84a070bd3", size = 259946, upload-time = "2025-08-17T00:26:15.899Z" }, - { url = "https://files.pythonhosted.org/packages/74/b2/49d82acefe2fe7c777436a3097f928c7242a842538b190f66aac01f29321/coverage-7.10.4-cp314-cp314t-win32.whl", hash = "sha256:e694d855dac2e7cf194ba33653e4ba7aad7267a802a7b3fc4347d0517d5d65cd", size = 220226, upload-time = "2025-08-17T00:26:17.566Z" }, - { url = "https://files.pythonhosted.org/packages/06/b0/afb942b6b2fc30bdbc7b05b087beae11c2b0daaa08e160586cf012b6ad70/coverage-7.10.4-cp314-cp314t-win_amd64.whl", hash = "sha256:efcc54b38ef7d5bfa98050f220b415bc5bb3d432bd6350a861cf6da0ede2cdcd", size = 221346, upload-time = "2025-08-17T00:26:19.311Z" }, - { url = "https://files.pythonhosted.org/packages/d8/66/e0531c9d1525cb6eac5b5733c76f27f3053ee92665f83f8899516fea6e76/coverage-7.10.4-cp314-cp314t-win_arm64.whl", hash = "sha256:6f3a3496c0fa26bfac4ebc458747b778cff201c8ae94fa05e1391bab0dbc473c", size = 219368, upload-time = "2025-08-17T00:26:21.011Z" }, - { url = "https://files.pythonhosted.org/packages/bb/78/983efd23200921d9edb6bd40512e1aa04af553d7d5a171e50f9b2b45d109/coverage-7.10.4-py3-none-any.whl", hash = "sha256:065d75447228d05121e5c938ca8f0e91eed60a1eb2d1258d42d5084fecfc3302", size = 208365, upload-time = "2025-08-17T00:26:41.479Z" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - -[[package]] -name = "deprecated" -version = "1.2.18" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "dpath" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/ce/e1fd64d36e4a5717bd5e6b2ad188f5eaa2e902fde871ea73a79875793fc9/dpath-2.2.0.tar.gz", hash = "sha256:34f7e630dc55ea3f219e555726f5da4b4b25f2200319c8e6902c394258dd6a3e", size = 28266, upload-time = "2024-06-12T22:08:03.686Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl", hash = "sha256:b330a375ded0a0d2ed404440f6c6a715deae5313af40bbb01c8a41d891900576", size = 17618, upload-time = "2024-06-12T22:08:01.881Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "executing" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.14" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ca/53/8c38a874844a8b0fa10dd8adf3836ac154082cf88d3f22b544e9ceea0a15/fastapi-0.115.14.tar.gz", hash = "sha256:b1de15cdc1c499a4da47914db35d0e4ef8f1ce62b624e94e0e5824421df99739", size = 296263, upload-time = "2025-06-26T15:29:08.21Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/50/b1222562c6d270fea83e9c9075b8e8600b8479150a18e4516a6138b980d1/fastapi-0.115.14-py3-none-any.whl", hash = "sha256:6c0c8bf9420bd58f565e585036d971872472b4f7d3f6c73b698e10cffdefb3ca", size = 95514, upload-time = "2025-06-26T15:29:06.49Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/94/3ef75d9c7c32936ecb539b9750ccbdc3d2568efd73b1cb913278375f4533/fastapi_cli-0.0.8.tar.gz", hash = "sha256:2360f2989b1ab4a3d7fc8b3a0b20e8288680d8af2e31de7c38309934d7f8a0ee", size = 16884, upload-time = "2025-07-07T14:44:09.326Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/3f/6ad3103c5f59208baf4c798526daea6a74085bb35d1c161c501863470476/fastapi_cli-0.0.8-py3-none-any.whl", hash = "sha256:0ea95d882c85b9219a75a65ab27e8da17dac02873e456850fa0a726e96e985eb", size = 10770, upload-time = "2025-07-07T14:44:08.255Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "fastapi-cloud-cli" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cloud-cli" -version = "0.1.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx" }, - { name = "pydantic", extra = ["email"] }, - { name = "rich-toolkit" }, - { name = "rignore" }, - { name = "sentry-sdk" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/2e/3b6e5016affc310e5109bc580f760586eabecea0c8a7ab067611cd849ac0/fastapi_cloud_cli-0.1.5.tar.gz", hash = "sha256:341ee585eb731a6d3c3656cb91ad38e5f39809bf1a16d41de1333e38635a7937", size = 22710, upload-time = "2025-07-28T13:30:48.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/a6/5aa862489a2918a096166fd98d9fe86b7fd53c607678b3fa9d8c432d88d5/fastapi_cloud_cli-0.1.5-py3-none-any.whl", hash = "sha256:d80525fb9c0e8af122370891f9fa83cf5d496e4ad47a8dd26c0496a6c85a012a", size = 18992, upload-time = "2025-07-28T13:30:47.427Z" }, -] - -[[package]] -name = "filelock" -version = "3.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, -] - -[[package]] -name = "fsspec" -version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/02/0835e6ab9cfc03916fe3f78c0956cfcdb6ff2669ffa6651065d5ebf7fc98/fsspec-2025.7.0.tar.gz", hash = "sha256:786120687ffa54b8283d942929540d8bc5ccfa820deb555a2b5d0ed2b737bf58", size = 304432, upload-time = "2025-07-15T16:05:21.19Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl", hash = "sha256:8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21", size = 199597, upload-time = "2025-07-15T16:05:19.529Z" }, -] - -[[package]] -name = "google-api-core" -version = "2.25.1" -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/dc/21/e9d043e88222317afdbdb567165fdbc3b0aad90064c7e0c9eb0ad9955ad8/google_api_core-2.25.1.tar.gz", hash = "sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8", size = 165443, upload-time = "2025-06-12T20:52:20.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/4b/ead00905132820b623732b175d66354e9d3e69fcf2a5dcdab780664e7896/google_api_core-2.25.1-py3-none-any.whl", hash = "sha256:8a2a56c1fef82987a524371f99f3bd0143702fecc670c72e600c1cda6bf8dbb7", size = 160807, upload-time = "2025-06-12T20:52:19.334Z" }, -] - -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, - { name = "grpcio-status" }, -] - -[[package]] -name = "google-auth" -version = "2.40.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029, upload-time = "2025-06-04T18:04:57.577Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137, upload-time = "2025-06-04T18:04:55.573Z" }, -] - -[[package]] -name = "google-cloud-monitoring" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/19/17b438b0fd628770ed01a79b8a2fcdbfb11a61a02bcdc769a225f50ea094/google_cloud_monitoring-2.27.2.tar.gz", hash = "sha256:d0f00205a5f94530dc72c3b96f681be14abdf1d6144dae5d2b922b54a90c43fa", size = 392827, upload-time = "2025-06-11T23:21:24.072Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/64/00a0027ee6bb6a69bc210037720477157e161ebcea20704c50fb0a7ba76f/google_cloud_monitoring-2.27.2-py3-none-any.whl", hash = "sha256:70b2e877d6267a3548ca17be301a4253fe83d4bebf7ea5cd8ee68b9dd3a70a02", size = 383687, upload-time = "2025-06-11T23:21:22.88Z" }, -] - -[[package]] -name = "google-cloud-trace" -version = "1.16.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/ea/0e42e2196fb2bc8c7b25f081a0b46b5053d160b34d5322e7eac2d5f7a742/google_cloud_trace-1.16.2.tar.gz", hash = "sha256:89bef223a512465951eb49335be6d60bee0396d576602dbf56368439d303cab4", size = 97826, upload-time = "2025-06-12T00:53:02.12Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/96/7a8d271e91effa9ccc2fd7cfd5cf287a2d7900080a475477c2ac0c7a331d/google_cloud_trace-1.16.2-py3-none-any.whl", hash = "sha256:40fb74607752e4ee0f3d7e5fc6b8f6eb1803982254a1507ba918172484131456", size = 103755, upload-time = "2025-06-12T00:53:00.672Z" }, -] - -[[package]] -name = "googleapis-common-protos" -version = "1.70.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, -] - -[[package]] -name = "greenlet" -version = "3.2.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, - { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, - { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, - { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, - { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, - { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, - { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, - { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, - { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, - { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, -] - -[[package]] -name = "grpcio" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/b4/35feb8f7cab7239c5b94bd2db71abb3d6adb5f335ad8f131abb6060840b6/grpcio-1.74.0.tar.gz", hash = "sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1", size = 12756048, upload-time = "2025-07-24T18:54:23.039Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d8/1004a5f468715221450e66b051c839c2ce9a985aa3ee427422061fcbb6aa/grpcio-1.74.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:2bc2d7d8d184e2362b53905cb1708c84cb16354771c04b490485fa07ce3a1d89", size = 5449488, upload-time = "2025-07-24T18:53:41.174Z" }, - { url = "https://files.pythonhosted.org/packages/94/0e/33731a03f63740d7743dced423846c831d8e6da808fcd02821a4416df7fa/grpcio-1.74.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c14e803037e572c177ba54a3e090d6eb12efd795d49327c5ee2b3bddb836bf01", size = 10974059, upload-time = "2025-07-24T18:53:43.066Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c6/3d2c14d87771a421205bdca991467cfe473ee4c6a1231c1ede5248c62ab8/grpcio-1.74.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:f6ec94f0e50eb8fa1744a731088b966427575e40c2944a980049798b127a687e", size = 5945647, upload-time = "2025-07-24T18:53:45.269Z" }, - { url = "https://files.pythonhosted.org/packages/c5/83/5a354c8aaff58594eef7fffebae41a0f8995a6258bbc6809b800c33d4c13/grpcio-1.74.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:566b9395b90cc3d0d0c6404bc8572c7c18786ede549cdb540ae27b58afe0fb91", size = 6626101, upload-time = "2025-07-24T18:53:47.015Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ca/4fdc7bf59bf6994aa45cbd4ef1055cd65e2884de6113dbd49f75498ddb08/grpcio-1.74.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1ea6176d7dfd5b941ea01c2ec34de9531ba494d541fe2057c904e601879f249", size = 6182562, upload-time = "2025-07-24T18:53:48.967Z" }, - { url = "https://files.pythonhosted.org/packages/fd/48/2869e5b2c1922583686f7ae674937986807c2f676d08be70d0a541316270/grpcio-1.74.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:64229c1e9cea079420527fa8ac45d80fc1e8d3f94deaa35643c381fa8d98f362", size = 6303425, upload-time = "2025-07-24T18:53:50.847Z" }, - { url = "https://files.pythonhosted.org/packages/a6/0e/bac93147b9a164f759497bc6913e74af1cb632c733c7af62c0336782bd38/grpcio-1.74.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:0f87bddd6e27fc776aacf7ebfec367b6d49cad0455123951e4488ea99d9b9b8f", size = 6996533, upload-time = "2025-07-24T18:53:52.747Z" }, - { url = "https://files.pythonhosted.org/packages/84/35/9f6b2503c1fd86d068b46818bbd7329db26a87cdd8c01e0d1a9abea1104c/grpcio-1.74.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3b03d8f2a07f0fea8c8f74deb59f8352b770e3900d143b3d1475effcb08eec20", size = 6491489, upload-time = "2025-07-24T18:53:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/75/33/a04e99be2a82c4cbc4039eb3a76f6c3632932b9d5d295221389d10ac9ca7/grpcio-1.74.0-cp313-cp313-win32.whl", hash = "sha256:b6a73b2ba83e663b2480a90b82fdae6a7aa6427f62bf43b29912c0cfd1aa2bfa", size = 3805811, upload-time = "2025-07-24T18:53:56.798Z" }, - { url = "https://files.pythonhosted.org/packages/34/80/de3eb55eb581815342d097214bed4c59e806b05f1b3110df03b2280d6dfd/grpcio-1.74.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24", size = 4489214, upload-time = "2025-07-24T18:53:59.771Z" }, -] - -[[package]] -name = "grpcio-status" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/93/22/238c5f01e6837df54494deb08d5c772bc3f5bf5fb80a15dce254892d1a81/grpcio_status-1.74.0.tar.gz", hash = "sha256:c58c1b24aa454e30f1fc6a7e0dbbc194c54a408143971a94b5f4e40bb5831432", size = 13662, upload-time = "2025-07-24T19:01:56.874Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/aa/1b1fe7d8ab699e1ec26d3a36b91d3df9f83a30abc07d4c881d0296b17b67/grpcio_status-1.74.0-py3-none-any.whl", hash = "sha256:52cdbd759a6760fc8f668098a03f208f493dd5c76bf8e02598bbbaf1f6fc2876", size = 14425, upload-time = "2025-07-24T19:01:19.963Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "h5py" -version = "3.14.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5d/57/dfb3c5c3f1bf5f5ef2e59a22dec4ff1f3d7408b55bfcefcfb0ea69ef21c6/h5py-3.14.0.tar.gz", hash = "sha256:2372116b2e0d5d3e5e705b7f663f7c8d96fa79a4052d250484ef91d24d6a08f4", size = 424323, upload-time = "2025-06-06T14:06:15.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/c2/7efe82d09ca10afd77cd7c286e42342d520c049a8c43650194928bcc635c/h5py-3.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa4b7bbce683379b7bf80aaba68e17e23396100336a8d500206520052be2f812", size = 3289245, upload-time = "2025-06-06T14:05:28.24Z" }, - { url = "https://files.pythonhosted.org/packages/4f/31/f570fab1239b0d9441024b92b6ad03bb414ffa69101a985e4c83d37608bd/h5py-3.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9603a501a04fcd0ba28dd8f0995303d26a77a980a1f9474b3417543d4c6174", size = 2807335, upload-time = "2025-06-06T14:05:31.997Z" }, - { url = "https://files.pythonhosted.org/packages/0d/ce/3a21d87896bc7e3e9255e0ad5583ae31ae9e6b4b00e0bcb2a67e2b6acdbc/h5py-3.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8cbaf6910fa3983c46172666b0b8da7b7bd90d764399ca983236f2400436eeb", size = 4700675, upload-time = "2025-06-06T14:05:37.38Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ec/86f59025306dcc6deee5fda54d980d077075b8d9889aac80f158bd585f1b/h5py-3.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d90e6445ab7c146d7f7981b11895d70bc1dd91278a4f9f9028bc0c95e4a53f13", size = 4921632, upload-time = "2025-06-06T14:05:43.464Z" }, - { url = "https://files.pythonhosted.org/packages/3f/6d/0084ed0b78d4fd3e7530c32491f2884140d9b06365dac8a08de726421d4a/h5py-3.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae18e3de237a7a830adb76aaa68ad438d85fe6e19e0d99944a3ce46b772c69b3", size = 2852929, upload-time = "2025-06-06T14:05:47.659Z" }, -] - -[[package]] -name = "hf-xet" -version = "1.1.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/0a/a0f56735940fde6dd627602fec9ab3bad23f66a272397560abd65aba416e/hf_xet-1.1.7.tar.gz", hash = "sha256:20cec8db4561338824a3b5f8c19774055b04a8df7fff0cb1ff2cb1a0c1607b80", size = 477719, upload-time = "2025-08-06T00:30:55.741Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/7c/8d7803995caf14e7d19a392a486a040f923e2cfeff824e9b800b92072f76/hf_xet-1.1.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:60dae4b44d520819e54e216a2505685248ec0adbdb2dd4848b17aa85a0375cde", size = 2761743, upload-time = "2025-08-06T00:30:50.634Z" }, - { url = "https://files.pythonhosted.org/packages/51/a3/fa5897099454aa287022a34a30e68dbff0e617760f774f8bd1db17f06bd4/hf_xet-1.1.7-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b109f4c11e01c057fc82004c9e51e6cdfe2cb230637644ade40c599739067b2e", size = 2624331, upload-time = "2025-08-06T00:30:49.212Z" }, - { url = "https://files.pythonhosted.org/packages/86/50/2446a132267e60b8a48b2e5835d6e24fd988000d0f5b9b15ebd6d64ef769/hf_xet-1.1.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6efaaf1a5a9fc3a501d3e71e88a6bfebc69ee3a716d0e713a931c8b8d920038f", size = 3183844, upload-time = "2025-08-06T00:30:47.582Z" }, - { url = "https://files.pythonhosted.org/packages/20/8f/ccc670616bb9beee867c6bb7139f7eab2b1370fe426503c25f5cbb27b148/hf_xet-1.1.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:751571540f9c1fbad9afcf222a5fb96daf2384bf821317b8bfb0c59d86078513", size = 3074209, upload-time = "2025-08-06T00:30:45.509Z" }, - { url = "https://files.pythonhosted.org/packages/21/0a/4c30e1eb77205565b854f5e4a82cf1f056214e4dc87f2918ebf83d47ae14/hf_xet-1.1.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:18b61bbae92d56ae731b92087c44efcac216071182c603fc535f8e29ec4b09b8", size = 3239602, upload-time = "2025-08-06T00:30:52.41Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1e/fc7e9baf14152662ef0b35fa52a6e889f770a7ed14ac239de3c829ecb47e/hf_xet-1.1.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:713f2bff61b252f8523739969f247aa354ad8e6d869b8281e174e2ea1bb8d604", size = 3348184, upload-time = "2025-08-06T00:30:54.105Z" }, - { url = "https://files.pythonhosted.org/packages/a3/73/e354eae84ceff117ec3560141224724794828927fcc013c5b449bf0b8745/hf_xet-1.1.7-cp37-abi3-win_amd64.whl", hash = "sha256:2e356da7d284479ae0f1dea3cf5a2f74fdf925d6dca84ac4341930d892c7cb34", size = 2820008, upload-time = "2025-08-06T00:30:57.056Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "huggingface-hub" -version = "0.34.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "importlib-metadata" -version = "8.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304, upload-time = "2024-09-11T14:56:08.937Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514, upload-time = "2024-09-11T14:56:07.019Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, -] - -[[package]] -name = "ipython" -version = "8.37.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088, upload-time = "2025-05-31T16:39:09.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864, upload-time = "2025-05-31T16:39:06.38Z" }, -] - -[[package]] -name = "jedi" -version = "0.19.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "jsonpickle" -version = "4.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/a6/d07afcfdef402900229bcca795f80506b207af13a838d4d99ad45abf530c/jsonpickle-4.1.1.tar.gz", hash = "sha256:f86e18f13e2b96c1c1eede0b7b90095bbb61d99fedc14813c44dc2f361dbbae1", size = 316885, upload-time = "2025-06-02T20:36:11.57Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/73/04df8a6fa66d43a9fd45c30f283cc4afff17da671886e451d52af60bdc7e/jsonpickle-4.1.1-py3-none-any.whl", hash = "sha256:bb141da6057898aa2438ff268362b126826c812a1721e31cf08a6e142910dc91", size = 47125, upload-time = "2025-06-02T20:36:08.647Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "4.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "matplotlib-inline" -version = "0.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "microdf-python" -version = "1.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "pandas" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/77/25/55c2b0495ae4c3142d61f1283d675494aac4c254e40ecf1ea4b337a051c7/microdf_python-1.0.2.tar.gz", hash = "sha256:5c845974d485598a7002c151f58ec7438e94c04954fc8fdea9238265e7bf02f5", size = 14826, upload-time = "2025-07-24T12:21:08.17Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/1a/aac40a7e58de4133a9cc7630913a8b8e6c76326288b168cbb47f7714c4fd/microdf_python-1.0.2-py3-none-any.whl", hash = "sha256:f7883785e4557d1c8822dbf0d69d7eeab9399f8e67a9bdb716f74554c7580ae7", size = 15823, upload-time = "2025-07-24T12:21:07.356Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - -[[package]] -name = "networkx" -version = "3.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, -] - -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] - -[[package]] -name = "numexpr" -version = "2.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d2/8f/2cc977e91adbfbcdb6b49fdb9147e1d1c7566eb2c0c1e737e9a47020b5ca/numexpr-2.11.0.tar.gz", hash = "sha256:75b2c01a4eda2e7c357bc67a3f5c3dd76506c15b5fd4dc42845ef2e182181bad", size = 108960, upload-time = "2025-06-09T11:05:56.79Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/74/63/dbf4fb6c48006d413a82db138d03c3c007d0ed0684f693c4b77196448660/numexpr-2.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eb766218abad05c7c3ddad5367d0ec702d6152cb4a48d9fd56a6cef6abade70c", size = 147495, upload-time = "2025-06-09T11:05:25.105Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/2fbbf5b9121f54722dc4d4dfc75bc0b4e8ee2675f92ec86ee5697aecc53f/numexpr-2.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2036be213a6a1b5ce49acf60de99b911a0f9d174aab7679dde1fae315134f826", size = 136839, upload-time = "2025-06-09T11:05:26.171Z" }, - { url = "https://files.pythonhosted.org/packages/a8/3f/aa36415919c90f712a11127eaa7c0c8d045768d62a484a29364e4801c383/numexpr-2.11.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:096ec768bee2ef14ac757b4178e3c5f05e5f1cb6cae83b2eea9b4ba3ec1a86dd", size = 416240, upload-time = "2025-06-09T11:05:27.634Z" }, - { url = "https://files.pythonhosted.org/packages/b9/7d/4911f40d3610fc5557029f0d1f20ef9f571488319567ac4d8ee6d0978ee6/numexpr-2.11.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1719788a787808c15c9bb98b6ff0c97d64a0e59c1a6ebe36d4ae4d7c5c09b95", size = 406641, upload-time = "2025-06-09T11:05:29.408Z" }, - { url = "https://files.pythonhosted.org/packages/6f/bc/d00e717e77691c410c6c461d7880b4c498896874316acc0e044d7eafacbf/numexpr-2.11.0-cp313-cp313-win32.whl", hash = "sha256:6b5fdfc86cbf5373ea67d554cc6f08863825ea8e928416bed8d5285e387420c6", size = 153313, upload-time = "2025-06-09T11:05:30.633Z" }, - { url = "https://files.pythonhosted.org/packages/52/a2/93346789e6d73a76fdb68171904ade25c112f25df363a8f602c6b21bc220/numexpr-2.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ff337b36db141a1a0b49f01282783744f49f0d401cc83a512fc5596eb7db5c6", size = 146340, upload-time = "2025-06-09T11:05:31.771Z" }, - { url = "https://files.pythonhosted.org/packages/0b/20/c0e3aaf3cc4497e5253df2523a55c83b9d316cb5c9d5caaa4a1156cef6e3/numexpr-2.11.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b9854fa70edbe93242b8bb4840e58d1128c45766d9a70710f05b4f67eb0feb6e", size = 148206, upload-time = "2025-06-09T11:05:33.3Z" }, - { url = "https://files.pythonhosted.org/packages/de/49/22fd38ac990ba333f25b771305a5ffcd98c771f4d278868661ffb26deac1/numexpr-2.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:321736cb98f090ce864b58cc5c37661cb5548e394e0fe24d5f2c7892a89070c3", size = 137573, upload-time = "2025-06-09T11:05:34.422Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1e/50074e472e9e6bea4fe430869708d9ede333a187d8d0740e70d5a9560aad/numexpr-2.11.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5cc434eb4a4df2fe442bcc50df114e82ff7aa234657baf873b2c9cf3f851e8e", size = 426674, upload-time = "2025-06-09T11:05:35.553Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6d/7ccbc72b950653df62d29e2531c811ed80cfff93c927a5bfd86a71edb4da/numexpr-2.11.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:238d19465a272ada3967600fada55e4c6900485aefb42122a78dfcaf2efca65f", size = 416037, upload-time = "2025-06-09T11:05:36.601Z" }, - { url = "https://files.pythonhosted.org/packages/31/7c/bbccad2734dd4b251cc6bdff8cf5ded18b5383f5a05aa8de7bf02acbb65b/numexpr-2.11.0-cp313-cp313t-win32.whl", hash = "sha256:0db4c2dcad09f9594b45fce794f4b903345195a8c216e252de2aa92884fd81a8", size = 153967, upload-time = "2025-06-09T11:05:37.907Z" }, - { url = "https://files.pythonhosted.org/packages/75/d7/41287384e413e8d20457d35e264d9c9754e65eb13a988af51ceb7057f61b/numexpr-2.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a69b5c02014448a412012752dc46091902d28932c3be0c6e02e73cecceffb700", size = 147207, upload-time = "2025-06-09T11:05:39.011Z" }, -] - -[[package]] -name = "numpy" -version = "2.1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090, upload-time = "2024-11-02T17:48:55.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/0b/620591441457e25f3404c8057eb924d04f161244cb8a3680d529419aa86e/numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f", size = 20836263, upload-time = "2024-11-02T17:40:39.528Z" }, - { url = "https://files.pythonhosted.org/packages/45/e1/210b2d8b31ce9119145433e6ea78046e30771de3fe353f313b2778142f34/numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598", size = 13507771, upload-time = "2024-11-02T17:41:01.368Z" }, - { url = "https://files.pythonhosted.org/packages/55/44/aa9ee3caee02fa5a45f2c3b95cafe59c44e4b278fbbf895a93e88b308555/numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57", size = 5075805, upload-time = "2024-11-02T17:41:11.213Z" }, - { url = "https://files.pythonhosted.org/packages/78/d6/61de6e7e31915ba4d87bbe1ae859e83e6582ea14c6add07c8f7eefd8488f/numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe", size = 6608380, upload-time = "2024-11-02T17:41:22.19Z" }, - { url = "https://files.pythonhosted.org/packages/3e/46/48bdf9b7241e317e6cf94276fe11ba673c06d1fdf115d8b4ebf616affd1a/numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43", size = 13602451, upload-time = "2024-11-02T17:41:43.094Z" }, - { url = "https://files.pythonhosted.org/packages/70/50/73f9a5aa0810cdccda9c1d20be3cbe4a4d6ea6bfd6931464a44c95eef731/numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56", size = 16039822, upload-time = "2024-11-02T17:42:07.595Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cd/098bc1d5a5bc5307cfc65ee9369d0ca658ed88fbd7307b0d49fab6ca5fa5/numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a", size = 16411822, upload-time = "2024-11-02T17:42:32.48Z" }, - { url = "https://files.pythonhosted.org/packages/83/a2/7d4467a2a6d984549053b37945620209e702cf96a8bc658bc04bba13c9e2/numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef", size = 14079598, upload-time = "2024-11-02T17:42:53.773Z" }, - { url = "https://files.pythonhosted.org/packages/e9/6a/d64514dcecb2ee70bfdfad10c42b76cab657e7ee31944ff7a600f141d9e9/numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f", size = 6236021, upload-time = "2024-11-02T17:46:19.171Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f9/12297ed8d8301a401e7d8eb6b418d32547f1d700ed3c038d325a605421a4/numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed", size = 12560405, upload-time = "2024-11-02T17:46:38.177Z" }, - { url = "https://files.pythonhosted.org/packages/a7/45/7f9244cd792e163b334e3a7f02dff1239d2890b6f37ebf9e82cbe17debc0/numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f", size = 20859062, upload-time = "2024-11-02T17:43:24.599Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b4/a084218e7e92b506d634105b13e27a3a6645312b93e1c699cc9025adb0e1/numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4", size = 13515839, upload-time = "2024-11-02T17:43:45.498Z" }, - { url = "https://files.pythonhosted.org/packages/27/45/58ed3f88028dcf80e6ea580311dc3edefdd94248f5770deb980500ef85dd/numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e", size = 5116031, upload-time = "2024-11-02T17:43:54.585Z" }, - { url = "https://files.pythonhosted.org/packages/37/a8/eb689432eb977d83229094b58b0f53249d2209742f7de529c49d61a124a0/numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0", size = 6629977, upload-time = "2024-11-02T17:44:05.31Z" }, - { url = "https://files.pythonhosted.org/packages/42/a3/5355ad51ac73c23334c7caaed01adadfda49544f646fcbfbb4331deb267b/numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408", size = 13575951, upload-time = "2024-11-02T17:44:25.881Z" }, - { url = "https://files.pythonhosted.org/packages/c4/70/ea9646d203104e647988cb7d7279f135257a6b7e3354ea6c56f8bafdb095/numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6", size = 16022655, upload-time = "2024-11-02T17:44:50.115Z" }, - { url = "https://files.pythonhosted.org/packages/14/ce/7fc0612903e91ff9d0b3f2eda4e18ef9904814afcae5b0f08edb7f637883/numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f", size = 16399902, upload-time = "2024-11-02T17:45:15.685Z" }, - { url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180, upload-time = "2024-11-02T17:45:37.234Z" }, - { url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907, upload-time = "2024-11-02T17:45:48.951Z" }, - { url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098, upload-time = "2024-11-02T17:46:07.941Z" }, -] - -[[package]] -name = "opentelemetry-api" -version = "1.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecated" }, - { name = "importlib-metadata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2b/6d/bbbf879826b7f3c89a45252010b5796fb1f1a0d45d9dc4709db0ef9a06c8/opentelemetry_api-1.30.0.tar.gz", hash = "sha256:375893400c1435bf623f7dfb3bcd44825fe6b56c34d0667c542ea8257b1a1240", size = 63703, upload-time = "2025-02-04T18:17:13.789Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/0a/eea862fae6413d8181b23acf8e13489c90a45f17986ee9cf4eab8a0b9ad9/opentelemetry_api-1.30.0-py3-none-any.whl", hash = "sha256:d5f5284890d73fdf47f843dda3210edf37a38d66f44f2b5aedc1e89ed455dc09", size = 64955, upload-time = "2025-02-04T18:16:46.167Z" }, -] - -[[package]] -name = "opentelemetry-exporter-gcp-monitoring" -version = "1.9.0a0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-cloud-monitoring" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-resourcedetector-gcp" }, - { name = "opentelemetry-sdk" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/b1/4ea1e384ffdc1d052fc333c699e35c843e92429d6fee4d7adad0f7cbf3b6/opentelemetry_exporter_gcp_monitoring-1.9.0a0.tar.gz", hash = "sha256:6ef8b76f5aaf78e0f2ef832b4d7e268553789265f7f3de328fd11fccf4aab5e5", size = 19757, upload-time = "2025-02-04T19:45:06.412Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/88/69dd7da2a7647dcfe47158dba2ba37f6b61e86d73ef2b9f56f03e1b3455c/opentelemetry_exporter_gcp_monitoring-1.9.0a0-py3-none-any.whl", hash = "sha256:dd6c0b5d6749f4a4c0c13f5d0b57cc6a280d3f8ec43befe016820d27aa29aa75", size = 13090, upload-time = "2025-02-04T19:44:56.881Z" }, -] - -[[package]] -name = "opentelemetry-exporter-gcp-trace" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-cloud-trace" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-resourcedetector-gcp" }, - { name = "opentelemetry-sdk" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c3/15/7556d54b01fb894497f69a98d57faa9caa45ffa59896e0bba6847a7f0d15/opentelemetry_exporter_gcp_trace-1.9.0.tar.gz", hash = "sha256:c3fc090342f6ee32a0cc41a5716a6bb716b4422d19facefcb22dc4c6b683ece8", size = 18568, upload-time = "2025-02-04T19:45:08.185Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/cd/6d7fbad05771eb3c2bace20f6360ce5dac5ca751c6f2122853e43830c32e/opentelemetry_exporter_gcp_trace-1.9.0-py3-none-any.whl", hash = "sha256:0a8396e8b39f636eeddc3f0ae08ddb40c40f288bc8c5544727c3581545e77254", size = 13973, upload-time = "2025-02-04T19:44:59.148Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "packaging" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/5a/4c7f02235ac1269b48f3855f6be1afc641f31d4888d28b90b732fbce7141/opentelemetry_instrumentation-0.51b0.tar.gz", hash = "sha256:4ca266875e02f3988536982467f7ef8c32a38b8895490ddce9ad9604649424fa", size = 27760, upload-time = "2025-02-04T18:21:09.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/2c/48fa93f1acca9f79a06da0df7bfe916632ecc7fce1971067b3e46bcae55b/opentelemetry_instrumentation-0.51b0-py3-none-any.whl", hash = "sha256:c6de8bd26b75ec8b0e54dff59e198946e29de6a10ec65488c357d4b34aa5bdcf", size = 30923, upload-time = "2025-02-04T18:19:37.829Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation-asgi" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asgiref" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "opentelemetry-util-http" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/67/8aa6e1129f641f0f3f8786e6c5d18c1f2bbe490bd4b0e91a6879e85154d2/opentelemetry_instrumentation_asgi-0.51b0.tar.gz", hash = "sha256:b3fe97c00f0bfa934371a69674981d76591c68d937b6422a5716ca21081b4148", size = 24201, upload-time = "2025-02-04T18:21:14.321Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/7e/0a95ab37302729543631a789ba8e71dea75c520495739dbbbdfdc580b401/opentelemetry_instrumentation_asgi-0.51b0-py3-none-any.whl", hash = "sha256:e8072993db47303b633c6ec1bc74726ba4d32bd0c46c28dfadf99f79521a324c", size = 16340, upload-time = "2025-02-04T18:19:49.924Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation-fastapi" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-instrumentation-asgi" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "opentelemetry-util-http" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/dc/8db4422b5084177d1ef6c7855c69bf2e9e689f595a4a9b59e60588e0d427/opentelemetry_instrumentation_fastapi-0.51b0.tar.gz", hash = "sha256:1624e70f2f4d12ceb792d8a0c331244cd6723190ccee01336273b4559bc13abc", size = 19249, upload-time = "2025-02-04T18:21:28.379Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/1c/ec2d816b78edf2404d7b3df6d09eefb690b70bfd191b7da06f76634f1bdc/opentelemetry_instrumentation_fastapi-0.51b0-py3-none-any.whl", hash = "sha256:10513bbc11a1188adb9c1d2c520695f7a8f2b5f4de14e8162098035901cd6493", size = 12117, upload-time = "2025-02-04T18:20:15.267Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation-logging" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/01/922f37e5d8c74bc3f92f24f3e240879ae1d04710fdeebb74f39914fc8467/opentelemetry_instrumentation_logging-0.51b0.tar.gz", hash = "sha256:2adaba90fab85a80de24728153b42ef2a74dd80fda5a3b17f3f95c11bb27c3ff", size = 9754, upload-time = "2025-02-04T18:21:33.947Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/e3/2d2390370b8730b6b9a2341892cd5508d0f5fa3fe30977457f89979d4085/opentelemetry_instrumentation_logging-0.51b0-py3-none-any.whl", hash = "sha256:b0855cf8b3e37ae4fdb5b77982fbfa713778762c58db3071eb3ca6c97456a049", size = 12171, upload-time = "2025-02-04T18:20:25.006Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation-sqlalchemy" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "packaging" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/b2/970b1b46576b663bba64503486afe266c064c2bfd1862876420714ce29d9/opentelemetry_instrumentation_sqlalchemy-0.51b0.tar.gz", hash = "sha256:dbfe95b69006017f903dda194606be458d54789e6b3419d37161fb8861bb98a5", size = 14582, upload-time = "2025-02-04T18:21:46.916Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/d4/b68c3b3388dd5107f3ed532747e112249c152ba44af71a1f96673d66e3ee/opentelemetry_instrumentation_sqlalchemy-0.51b0-py3-none-any.whl", hash = "sha256:5ff4816228b496aef1511149e2b17a25e0faacec4d5eb65bf18a9964af40f1af", size = 14132, upload-time = "2025-02-04T18:20:50.513Z" }, -] - -[[package]] -name = "opentelemetry-resourcedetector-gcp" -version = "1.9.0a0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-sdk" }, - { name = "requests" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/86/f0693998817779802525a5bcc885a3cdb68d05b636bc6faae5c9ade4bee4/opentelemetry_resourcedetector_gcp-1.9.0a0.tar.gz", hash = "sha256:6860a6649d1e3b9b7b7f09f3918cc16b72aa0c0c590d2a72ea6e42b67c9a42e7", size = 20730, upload-time = "2025-02-04T19:45:10.693Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/04/7e33228c88422a5518e1774a836c9ec68f10f51bde0f1d5dd5f3054e612a/opentelemetry_resourcedetector_gcp-1.9.0a0-py3-none-any.whl", hash = "sha256:4e5a0822b0f0d7647b7ceb282d7aa921dd7f45466540bd0a24f954f90db8fde8", size = 20378, upload-time = "2025-02-04T19:45:03.898Z" }, -] - -[[package]] -name = "opentelemetry-sdk" -version = "1.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/93/ee/d710062e8a862433d1be0b85920d0c653abe318878fef2d14dfe2c62ff7b/opentelemetry_sdk-1.30.0.tar.gz", hash = "sha256:c9287a9e4a7614b9946e933a67168450b9ab35f08797eb9bc77d998fa480fa18", size = 158633, upload-time = "2025-02-04T18:17:28.908Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/28/64d781d6adc6bda2260067ce2902bd030cf45aec657e02e28c5b4480b976/opentelemetry_sdk-1.30.0-py3-none-any.whl", hash = "sha256:14fe7afc090caad881addb6926cec967129bd9260c4d33ae6a217359f6b61091", size = 118717, upload-time = "2025-02-04T18:17:09.353Z" }, -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecated" }, - { name = "opentelemetry-api" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1e/c0/0f9ef4605fea7f2b83d55dd0b0d7aebe8feead247cd6facd232b30907b4f/opentelemetry_semantic_conventions-0.51b0.tar.gz", hash = "sha256:3fabf47f35d1fd9aebcdca7e6802d86bd5ebc3bc3408b7e3248dde6e87a18c47", size = 107191, upload-time = "2025-02-04T18:17:29.903Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/75/d7bdbb6fd8630b4cafb883482b75c4fc276b6426619539d266e32ac53266/opentelemetry_semantic_conventions-0.51b0-py3-none-any.whl", hash = "sha256:fdc777359418e8d06c86012c3dc92c88a6453ba662e941593adb062e48c2eeae", size = 177416, upload-time = "2025-02-04T18:17:11.305Z" }, -] - -[[package]] -name = "opentelemetry-util-http" -version = "0.51b0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/64/32510c0a803465eb6ef1f5bd514d0f5627f8abc9444ed94f7240faf6fcaa/opentelemetry_util_http-0.51b0.tar.gz", hash = "sha256:05edd19ca1cc3be3968b1e502fd94816901a365adbeaab6b6ddb974384d3a0b9", size = 8043, upload-time = "2025-02-04T18:21:59.811Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/dd/c371eeb9cc78abbdad231a27ce1a196a37ef96328d876ccbb381dea4c8ee/opentelemetry_util_http-0.51b0-py3-none-any.whl", hash = "sha256:0561d7a6e9c422b9ef9ae6e77eafcfcd32a2ab689f5e801475cbb67f189efa20", size = 7304, upload-time = "2025-02-04T18:21:05.483Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "pandas" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/ed/ff0a67a2c5505e1854e6715586ac6693dd860fbf52ef9f81edee200266e7/pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22", size = 11531393, upload-time = "2025-07-07T19:19:12.245Z" }, - { url = "https://files.pythonhosted.org/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a", size = 10668750, upload-time = "2025-07-07T19:19:14.612Z" }, - { url = "https://files.pythonhosted.org/packages/0f/b0/80f6ec783313f1e2356b28b4fd8d2148c378370045da918c73145e6aab50/pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928", size = 11342004, upload-time = "2025-07-07T19:19:16.857Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e2/20a317688435470872885e7fc8f95109ae9683dec7c50be29b56911515a5/pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9", size = 12050869, upload-time = "2025-07-07T19:19:19.265Z" }, - { url = "https://files.pythonhosted.org/packages/55/79/20d746b0a96c67203a5bee5fb4e00ac49c3e8009a39e1f78de264ecc5729/pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12", size = 12750218, upload-time = "2025-07-07T19:19:21.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0f/145c8b41e48dbf03dd18fdd7f24f8ba95b8254a97a3379048378f33e7838/pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb", size = 13416763, upload-time = "2025-07-07T19:19:23.939Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956", size = 10987482, upload-time = "2025-07-07T19:19:42.699Z" }, - { url = "https://files.pythonhosted.org/packages/48/64/2fd2e400073a1230e13b8cd604c9bc95d9e3b962e5d44088ead2e8f0cfec/pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a", size = 12029159, upload-time = "2025-07-07T19:19:26.362Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0a/d84fd79b0293b7ef88c760d7dca69828d867c89b6d9bc52d6a27e4d87316/pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9", size = 11393287, upload-time = "2025-07-07T19:19:29.157Z" }, - { url = "https://files.pythonhosted.org/packages/50/ae/ff885d2b6e88f3c7520bb74ba319268b42f05d7e583b5dded9837da2723f/pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275", size = 11309381, upload-time = "2025-07-07T19:19:31.436Z" }, - { url = "https://files.pythonhosted.org/packages/85/86/1fa345fc17caf5d7780d2699985c03dbe186c68fee00b526813939062bb0/pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab", size = 11883998, upload-time = "2025-07-07T19:19:34.267Z" }, - { url = "https://files.pythonhosted.org/packages/81/aa/e58541a49b5e6310d89474333e994ee57fea97c8aaa8fc7f00b873059bbf/pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96", size = 12704705, upload-time = "2025-07-07T19:19:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" }, -] - -[[package]] -name = "parso" -version = "0.8.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, -] - -[[package]] -name = "platformdirs" -version = "4.3.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, -] - -[[package]] -name = "plotly" -version = "5.24.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "tenacity" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/79/4f/428f6d959818d7425a94c190a6b26fbc58035cbef40bf249be0b62a9aedd/plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae", size = 9479398, upload-time = "2024-09-12T15:36:31.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/ae/580600f441f6fc05218bd6c9d5794f4aef072a7d9093b291f1c50a9db8bc/plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089", size = 19054220, upload-time = "2024-09-12T15:36:24.08Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "policyengine-core" -version = "3.20.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dpath" }, - { name = "h5py" }, - { name = "huggingface-hub" }, - { name = "ipython" }, - { name = "microdf-python" }, - { name = "numexpr" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "plotly" }, - { name = "psutil" }, - { name = "pytest" }, - { name = "pyvis" }, - { name = "requests" }, - { name = "sortedcontainers" }, - { name = "standard-imghdr" }, - { name = "wheel" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d3/d7/cd4ae165221b3d5630a5c95e6df0a10be06d461b6545552a5f4a11c40907/policyengine_core-3.20.0.tar.gz", hash = "sha256:10c428467c8629861986f356f7f13ff8bf23ec907961779cf9f6add63f147fdf", size = 159655, upload-time = "2025-08-12T15:54:35.437Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/47/9cd4a2cfd675c5267dc905b2f23313b37df734f94f65490ca083422db39f/policyengine_core-3.20.0-py3-none-any.whl", hash = "sha256:c802edf10059242f7c03b54f7e8c78703ae053defcfe4ec75c677ed0714c07a6", size = 220871, upload-time = "2025-08-12T15:54:33.799Z" }, -] - -[[package]] -name = "policyengine-fastapi" -version = "0.1.0" -source = { editable = "../../libs/policyengine-fastapi" } -dependencies = [ - { name = "fastapi", extra = ["standard"] }, - { name = "opentelemetry-exporter-gcp-monitoring" }, - { name = "opentelemetry-exporter-gcp-trace" }, - { name = "opentelemetry-instrumentation-fastapi" }, - { name = "opentelemetry-instrumentation-logging" }, - { name = "opentelemetry-instrumentation-sqlalchemy" }, - { name = "opentelemetry-sdk" }, - { name = "pyjwt" }, - { name = "python-json-logger" }, - { name = "sqlmodel" }, - { name = "uvicorn" }, -] - -[package.metadata] -requires-dist = [ - { name = "black", marker = "extra == 'build'", specifier = ">=25.1.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.8,<0.116.0" }, - { name = "opentelemetry-exporter-gcp-monitoring", specifier = ">=1.9.0a0,<2.0.0" }, - { name = "opentelemetry-exporter-gcp-trace", specifier = ">=1.9.0,<2.0.0" }, - { name = "opentelemetry-instrumentation-fastapi", specifier = ">=0.51b0,<0.52" }, - { name = "opentelemetry-instrumentation-logging", specifier = ">=0.51b0,<0.52" }, - { name = "opentelemetry-instrumentation-sqlalchemy", specifier = ">=0.51b0" }, - { name = "opentelemetry-sdk", specifier = ">=1.30.0,<2.0.0" }, - { name = "pyjwt", specifier = ">=2.10.1,<3.0.0" }, - { name = "pyright", marker = "extra == 'build'", specifier = ">=1.1.401" }, - { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3.4" }, - { name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.25.3" }, - { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=6.1.1" }, - { name = "python-json-logger", specifier = ">=3.2.1,<4.0.0" }, - { name = "sqlmodel", specifier = ">=0.0.22,<0.0.23" }, - { name = "uvicorn", specifier = ">=0.35.0" }, -] -provides-extras = ["test", "build"] - -[[package]] -name = "policyengine-household-api" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "fastapi" }, - { name = "numpy" }, - { name = "opentelemetry-instrumentation-fastapi" }, - { name = "opentelemetry-instrumentation-sqlalchemy" }, - { name = "policyengine-fastapi" }, - { name = "policyengine-il" }, - { name = "policyengine-ng" }, - { name = "policyengine-uk" }, - { name = "policyengine-us" }, - { name = "pydantic-settings" }, -] - -[package.optional-dependencies] -build = [ - { name = "black" }, - { name = "pyright" }, -] -test = [ - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "pytest-cov" }, -] - -[package.metadata] -requires-dist = [ - { name = "black", marker = "extra == 'build'", specifier = ">=25.1.0" }, - { name = "fastapi", specifier = ">=0.115.8,<0.116.0" }, - { name = "numpy", specifier = ">=2.0.0,<3.0.0" }, - { name = "opentelemetry-instrumentation-fastapi", specifier = ">=0.51b0,<0.52" }, - { name = "opentelemetry-instrumentation-sqlalchemy", specifier = ">=0.51b0,<0.52" }, - { name = "policyengine-fastapi", editable = "../../libs/policyengine-fastapi" }, - { name = "policyengine-il", specifier = ">=0.1.0" }, - { name = "policyengine-ng", specifier = ">=0.5.1" }, - { name = "policyengine-uk", specifier = ">=2.19.1" }, - { name = "policyengine-us", specifier = ">=1.202.2,<1.338.0" }, - { name = "pydantic-settings", specifier = ">=2.7.1,<3.0.0" }, - { name = "pyright", marker = "extra == 'build'", specifier = ">=1.1.401" }, - { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3.4" }, - { name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.25.3" }, - { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=6.1.1" }, -] -provides-extras = ["test", "build"] - -[[package]] -name = "policyengine-il" -version = "0.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "policyengine-core" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/95/8ef0c26e4f21f28d0f424db6ac34111d966035f10501122c8de02944370b/policyengine-il-0.1.0.tar.gz", hash = "sha256:07ce41e50baeb538216f6a13f32a232bcb2a5bb2b9f37856e453b47de3117190", size = 20755, upload-time = "2023-07-06T16:37:46.229Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/59/55/ae00fc43b1e2b47075dc8bf7d259c837e043f82d23ac4909dfd5ed8367a6/policyengine_il-0.1.0-py3-none-any.whl", hash = "sha256:cc30402d1457862b1d1c3a2742eadfdb41dedc547c6508fa548b26db6e7658e8", size = 29342, upload-time = "2023-07-06T16:37:44.831Z" }, -] - -[[package]] -name = "policyengine-ng" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "policyengine-core" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/6a/2e60ecef7b3bb51073b6323c019211716ee0621638337d435bea1d919653/policyengine-ng-0.5.1.tar.gz", hash = "sha256:0d93d2c2728146385a4208ef3da516e26281b58459e2e1a538bbaa91d76f29d3", size = 36955, upload-time = "2023-04-19T13:13:41.012Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/9e/1040e63f72f3857d540e52c0f99115f8db04da5e94231959d4245a119bef/policyengine_ng-0.5.1-py3-none-any.whl", hash = "sha256:21fad6aae8d80a156142ac876cf1b7679e036c1640ca6cb375661701f10b9920", size = 31074, upload-time = "2023-04-19T13:14:28.242Z" }, -] - -[[package]] -name = "policyengine-uk" -version = "2.47.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "microdf-python" }, - { name = "policyengine-core" }, - { name = "pydantic" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d9/62/e9aa51662a71eae82be6bb2ef1bd4f92e8cfee0a9c182531f9fbc726ce85/policyengine_uk-2.47.4.tar.gz", hash = "sha256:28b324a3da198fef7e1c8440599e9a2edee786b98524dacf6302bd2eb5e80276", size = 1045333, upload-time = "2025-08-14T16:31:55.82Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/2f/8788e25b7b94514ab469e0b8c29a0299c56eef0ff9dcf7af0bf894c3cc80/policyengine_uk-2.47.4-py3-none-any.whl", hash = "sha256:63f23b131f44bb52311b239ee0db6a9818dcccab59c3b30917e8546b5a015134", size = 1601794, upload-time = "2025-08-14T16:31:54.111Z" }, -] - -[[package]] -name = "policyengine-us" -version = "1.337.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "microdf-python" }, - { name = "policyengine-core" }, - { name = "policyengine-us-data" }, - { name = "tqdm" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/1d/61434dc3d19a2c8cc36f7f856a2c819cde7d51f8503cdbd27a74e0db8067/policyengine_us-1.337.0.tar.gz", hash = "sha256:8c0d737e38a474241541fc84fd1073eb98db6caf53f9b623f396201c3fae4a77", size = 1923273, upload-time = "2025-07-08T19:01:43.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/58/53329a5f0cd3d360ed4707f60d0c0aac6401159001ce12368552e51a6e75/policyengine_us-1.337.0-py3-none-any.whl", hash = "sha256:750d40a8f4b434369f4a13bc5abc07291f2dbcb60b1ab40661ad1672af575051", size = 5706106, upload-time = "2025-07-08T19:01:39.167Z" }, -] - -[[package]] -name = "policyengine-us-data" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "microdf-python" }, - { name = "policyengine-core" }, - { name = "policyengine-us" }, - { name = "requests" }, - { name = "tqdm" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/16/3f68f123903fe9a2e0746e0f2a82344d1b9250c1a3ff471a3a43b465725b/policyengine_us_data-1.17.0.tar.gz", hash = "sha256:e692232d826b2f9c99e36d2625dce55e8025d3d669cd4425465bc671993fd003", size = 2775357, upload-time = "2025-01-24T11:21:10.686Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/d5/ce7498ee87669cc72fefc35e1b2f77221ea61f397742c08c1e57f1aa74fe/policyengine_us_data-1.17.0-py3-none-any.whl", hash = "sha256:66d6bdd608d3a2f0051a621cce7d61fc8cab799a3725e7fe72725d65ac9b8a3a", size = 463194, upload-time = "2025-01-24T11:21:09.159Z" }, -] - -[[package]] -name = "prompt-toolkit" -version = "3.0.51" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, -] - -[[package]] -name = "proto-plus" -version = "1.26.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" }, -] - -[[package]] -name = "protobuf" -version = "6.32.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c0/df/fb4a8eeea482eca989b51cffd274aac2ee24e825f0bf3cbce5281fa1567b/protobuf-6.32.0.tar.gz", hash = "sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2", size = 440614, upload-time = "2025-08-14T21:21:25.015Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/18/df8c87da2e47f4f1dcc5153a81cd6bca4e429803f4069a299e236e4dd510/protobuf-6.32.0-cp310-abi3-win32.whl", hash = "sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741", size = 424409, upload-time = "2025-08-14T21:21:12.366Z" }, - { url = "https://files.pythonhosted.org/packages/e1/59/0a820b7310f8139bd8d5a9388e6a38e1786d179d6f33998448609296c229/protobuf-6.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e", size = 435735, upload-time = "2025-08-14T21:21:15.046Z" }, - { url = "https://files.pythonhosted.org/packages/cc/5b/0d421533c59c789e9c9894683efac582c06246bf24bb26b753b149bd88e4/protobuf-6.32.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0", size = 426449, upload-time = "2025-08-14T21:21:16.687Z" }, - { url = "https://files.pythonhosted.org/packages/ec/7b/607764ebe6c7a23dcee06e054fd1de3d5841b7648a90fd6def9a3bb58c5e/protobuf-6.32.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1", size = 322869, upload-time = "2025-08-14T21:21:18.282Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/2e730bd1c25392fc32e3268e02446f0d77cb51a2c3a8486b1798e34d5805/protobuf-6.32.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c", size = 322009, upload-time = "2025-08-14T21:21:19.893Z" }, - { url = "https://files.pythonhosted.org/packages/9c/f2/80ffc4677aac1bc3519b26bc7f7f5de7fce0ee2f7e36e59e27d8beb32dd1/protobuf-6.32.0-py3-none-any.whl", hash = "sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783", size = 169287, upload-time = "2025-08-14T21:21:23.515Z" }, -] - -[[package]] -name = "psutil" -version = "6.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502, upload-time = "2024-12-19T18:21:20.568Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511, upload-time = "2024-12-19T18:21:45.163Z" }, - { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985, upload-time = "2024-12-19T18:21:49.254Z" }, - { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488, upload-time = "2024-12-19T18:21:51.638Z" }, - { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477, upload-time = "2024-12-19T18:21:55.306Z" }, - { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017, upload-time = "2024-12-19T18:21:57.875Z" }, - { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602, upload-time = "2024-12-19T18:22:08.808Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444, upload-time = "2024-12-19T18:22:11.335Z" }, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, -] - -[[package]] -name = "pyasn1" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, -] - -[[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, upload-time = "2025-03-28T02:41:22.17Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, -] - -[[package]] -name = "pydantic" -version = "2.11.7" -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/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, -] - -[package.optional-dependencies] -email = [ - { name = "email-validator" }, -] - -[[package]] -name = "pydantic-core" -version = "2.33.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, - { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, - { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, - { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, - { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, - { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[[package]] -name = "pyright" -version = "1.1.403" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/f6/35f885264ff08c960b23d1542038d8da86971c5d8c955cfab195a4f672d7/pyright-1.1.403.tar.gz", hash = "sha256:3ab69b9f41c67fb5bbb4d7a36243256f0d549ed3608678d381d5f51863921104", size = 3913526, upload-time = "2025-07-09T07:15:52.882Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/b6/b04e5c2f41a5ccad74a1a4759da41adb20b4bc9d59a5e08d29ba60084d07/pyright-1.1.403-py3-none-any.whl", hash = "sha256:c0eeca5aa76cbef3fcc271259bbd785753c7ad7bcac99a9162b4c4c7daed23b3", size = 5684504, upload-time = "2025-07-09T07:15:50.958Z" }, -] - -[[package]] -name = "pytest" -version = "8.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, -] - -[[package]] -name = "pytest-asyncio" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4e/51/f8794af39eeb870e87a8c8068642fc07bce0c854d6865d7dd0f2a9d338c2/pytest_asyncio-1.1.0.tar.gz", hash = "sha256:796aa822981e01b68c12e4827b8697108f7205020f24b5793b3c41555dab68ea", size = 46652, upload-time = "2025-07-16T04:29:26.393Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157, upload-time = "2025-07-16T04:29:24.929Z" }, -] - -[[package]] -name = "pytest-cov" -version = "6.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coverage" }, - { name = "pluggy" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, -] - -[[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, upload-time = "2024-03-01T18:36:20.211Z" } -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, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, -] - -[[package]] -name = "python-json-logger" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, -] - -[[package]] -name = "pyvis" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipython" }, - { name = "jinja2" }, - { name = "jsonpickle" }, - { name = "networkx" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4b/e37e4e5d5ee1179694917b445768bdbfb084f5a59ecd38089d3413d4c70f/pyvis-0.3.2-py3-none-any.whl", hash = "sha256:5720c4ca8161dc5d9ab352015723abb7a8bb8fb443edeb07f7a322db34a97555", size = 756038, upload-time = "2023-02-24T20:29:46.758Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/65/36/cdb3d51371ad0cccbf1541506304783bd72d55790709b8eb68c0d401a13a/rich_toolkit-0.15.0.tar.gz", hash = "sha256:3f5730e9f2d36d0bfe01cf723948b7ecf4cc355d2b71e2c00e094f7963128c09", size = 115118, upload-time = "2025-08-11T10:55:37.909Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/e4/b0794eefb3cf78566b15e5bf576492c1d4a92ce5f6da55675bc11e9ef5d8/rich_toolkit-0.15.0-py3-none-any.whl", hash = "sha256:ddb91008283d4a7989fd8ff0324a48773a7a2276229c6a3070755645538ef1bb", size = 29062, upload-time = "2025-08-11T10:55:37.152Z" }, -] - -[[package]] -name = "rignore" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/46/05a94dc55ac03cf931d18e43b86ecee5ee054cb88b7853fffd741e35009c/rignore-0.6.4.tar.gz", hash = "sha256:e893fdd2d7fdcfa9407d0b7600ef2c2e2df97f55e1c45d4a8f54364829ddb0ab", size = 11633, upload-time = "2025-07-19T19:24:46.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/a3/edd7d0d5cc0720de132b6651cef95ee080ce5fca11c77d8a47db848e5f90/rignore-0.6.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2b3b1e266ce45189240d14dfa1057f8013ea34b9bc8b3b44125ec8d25fdb3985", size = 885304, upload-time = "2025-07-19T19:23:54.268Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/d8d2fb97a6548307507d049b7e93885d4a0dfa1c907af5983fd9f9362a21/rignore-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45fe803628cc14714df10e8d6cdc23950a47eb9eb37dfea9a4779f4c672d2aa0", size = 818799, upload-time = "2025-07-19T19:23:47.544Z" }, - { url = "https://files.pythonhosted.org/packages/b1/cd/949981fcc180ad5ba7b31c52e78b74b2dea6b7bf744ad4c0c4b212f6da78/rignore-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e439f034277a947a4126e2da79dbb43e33d73d7c09d3d72a927e02f8a16f59aa", size = 892024, upload-time = "2025-07-19T19:22:36.18Z" }, - { url = "https://files.pythonhosted.org/packages/b0/d3/9042d701a8062d9c88f87760bbc2695ee2c23b3f002d34486b72a85f8efe/rignore-0.6.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84b5121650ae24621154c7bdba8b8970b0739d8146505c9f38e0cda9385d1004", size = 871430, upload-time = "2025-07-19T19:22:49.62Z" }, - { url = "https://files.pythonhosted.org/packages/eb/50/3370249b984212b7355f3d9241aa6d02e706067c6d194a2614dfbc0f5b27/rignore-0.6.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52b0957b585ab48a445cf8ac1dbc33a272ab060835e583b4f95aa8c67c23fb2b", size = 1160559, upload-time = "2025-07-19T19:23:01.629Z" }, - { url = "https://files.pythonhosted.org/packages/6c/6f/2ad7f925838091d065524f30a8abda846d1813eee93328febf262b5cda21/rignore-0.6.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50359e0d5287b5e2743bd2f2fbf05df619c8282fd3af12f6628ff97b9675551d", size = 939947, upload-time = "2025-07-19T19:23:14.608Z" }, - { url = "https://files.pythonhosted.org/packages/1f/01/626ec94d62475ae7ef8b00ef98cea61cbea52a389a666703c97c4673d406/rignore-0.6.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe18096dcb1596757dfe0b412aab6d32564473ae7ee58dea0a8b4be5b1a2e3b", size = 949471, upload-time = "2025-07-19T19:23:37.521Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c3/699c4f03b3c46f4b5c02f17a0a339225da65aad547daa5b03001e7c6a382/rignore-0.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b79c212d9990a273ad91e8d9765e1766ef6ecedd3be65375d786a252762ba385", size = 974912, upload-time = "2025-07-19T19:23:27.13Z" }, - { url = "https://files.pythonhosted.org/packages/cd/35/04626c12f9f92a9fc789afc2be32838a5d9b23b6fa8b2ad4a8625638d15b/rignore-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6ffa7f2a8894c65aa5dc4e8ac8bbdf39a326c0c6589efd27686cfbb48f0197d", size = 1067281, upload-time = "2025-07-19T19:24:01.016Z" }, - { url = "https://files.pythonhosted.org/packages/fe/9c/8f17baf3b984afea151cb9094716f6f1fb8e8737db97fc6eb6d494bd0780/rignore-0.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a63f5720dffc8d8fb0a4d02fafb8370a4031ebf3f99a4e79f334a91e905b7349", size = 1134414, upload-time = "2025-07-19T19:24:13.534Z" }, - { url = "https://files.pythonhosted.org/packages/10/88/ef84ffa916a96437c12cefcc39d474122da9626d75e3a2ebe09ec5d32f1b/rignore-0.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ce33982da47ac5dc09d19b04fa8d7c9aa6292fc0bd1ecf33076989faa8886094", size = 1109330, upload-time = "2025-07-19T19:24:25.303Z" }, - { url = "https://files.pythonhosted.org/packages/27/43/2ada5a2ec03b82e903610a1c483f516f78e47700ee6db9823f739e08b3af/rignore-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d899621867aa266824fbd9150e298f19d25b93903ef0133c09f70c65a3416eca", size = 1120381, upload-time = "2025-07-19T19:24:37.798Z" }, - { url = "https://files.pythonhosted.org/packages/3b/99/e7bcc643085131cb14dbea772def72bf1f6fe9037171ebe177c4f228abc8/rignore-0.6.4-cp313-cp313-win32.whl", hash = "sha256:d0615a6bf4890ec5a90b5fb83666822088fbd4e8fcd740c386fcce51e2f6feea", size = 641761, upload-time = "2025-07-19T19:24:58.096Z" }, - { url = "https://files.pythonhosted.org/packages/d9/25/7798908044f27dea1a8abdc75c14523e33770137651e5f775a15143f4218/rignore-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:145177f0e32716dc2f220b07b3cde2385b994b7ea28d5c96fbec32639e9eac6f", size = 719876, upload-time = "2025-07-19T19:24:51.125Z" }, - { url = "https://files.pythonhosted.org/packages/b4/e3/ae1e30b045bf004ad77bbd1679b9afff2be8edb166520921c6f29420516a/rignore-0.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e55bf8f9bbd186f58ab646b4a08718c77131d28a9004e477612b0cbbd5202db2", size = 891776, upload-time = "2025-07-19T19:22:37.78Z" }, - { url = "https://files.pythonhosted.org/packages/45/a9/1193e3bc23ca0e6eb4f17cf4b99971237f97cfa6f241d98366dff90a6d09/rignore-0.6.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2521f7bf3ee1f2ab22a100a3a4eed39a97b025804e5afe4323528e9ce8f084a5", size = 871442, upload-time = "2025-07-19T19:22:50.972Z" }, - { url = "https://files.pythonhosted.org/packages/20/83/4c52ae429a0b2e1ce667e35b480e9a6846f9468c443baeaed5d775af9485/rignore-0.6.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cc35773a8a9c119359ef974d0856988d4601d4daa6f532c05f66b4587cf35bc", size = 1159844, upload-time = "2025-07-19T19:23:02.751Z" }, - { url = "https://files.pythonhosted.org/packages/c1/2f/c740f5751f464c937bfe252dc15a024ae081352cfe80d94aa16d6a617482/rignore-0.6.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b665b1ea14457d7b49e834baabc635a3b8c10cfb5cca5c21161fabdbfc2b850e", size = 939456, upload-time = "2025-07-19T19:23:15.72Z" }, - { url = "https://files.pythonhosted.org/packages/fc/dd/68dbb08ac0edabf44dd144ff546a3fb0253c5af708e066847df39fc9188f/rignore-0.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c7fd339f344a8548724f289495b835bed7b81174a0bc1c28c6497854bd8855db", size = 1067070, upload-time = "2025-07-19T19:24:02.803Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3a/7e7ea6f0d31d3f5beb0f2cf2c4c362672f5f7f125714458673fc579e2bed/rignore-0.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:91dc94b1cc5af8d6d25ce6edd29e7351830f19b0a03b75cb3adf1f76d00f3007", size = 1134598, upload-time = "2025-07-19T19:24:15.039Z" }, - { url = "https://files.pythonhosted.org/packages/7e/06/1b3307f6437d29bede5a95738aa89e6d910ba68d4054175c9f60d8e2c6b1/rignore-0.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4d1918221a249e5342b60fd5fa513bf3d6bf272a8738e66023799f0c82ecd788", size = 1108862, upload-time = "2025-07-19T19:24:26.765Z" }, - { url = "https://files.pythonhosted.org/packages/b0/d5/b37c82519f335f2c472a63fc6215c6f4c51063ecf3166e3acf508011afbd/rignore-0.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:240777332b859dc89dcba59ab6e3f1e062bc8e862ffa3e5f456e93f7fd5cb415", size = 1120002, upload-time = "2025-07-19T19:24:38.952Z" }, - { url = "https://files.pythonhosted.org/packages/ac/72/2f05559ed5e69bdfdb56ea3982b48e6c0017c59f7241f7e1c5cae992b347/rignore-0.6.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b0e548753e55cc648f1e7b02d9f74285fe48bb49cec93643d31e563773ab3f", size = 949454, upload-time = "2025-07-19T19:23:38.664Z" }, - { url = "https://files.pythonhosted.org/packages/0b/92/186693c8f838d670510ac1dfb35afbe964320fbffb343ba18f3d24441941/rignore-0.6.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6971ac9fdd5a0bd299a181096f091c4f3fd286643adceba98eccc03c688a6637", size = 974663, upload-time = "2025-07-19T19:23:28.24Z" }, -] - -[[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, upload-time = "2025-04-16T09:51:18.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, -] - -[[package]] -name = "sentry-sdk" -version = "2.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/31/83/055dc157b719651ef13db569bb8cf2103df11174478649735c1b2bf3f6bc/sentry_sdk-2.35.0.tar.gz", hash = "sha256:5ea58d352779ce45d17bc2fa71ec7185205295b83a9dbb5707273deb64720092", size = 343014, upload-time = "2025-08-14T17:11:20.223Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3d/742617a7c644deb0c1628dcf6bb2d2165ab7c6aab56fe5222758994007f8/sentry_sdk-2.35.0-py2.py3-none-any.whl", hash = "sha256:6e0c29b9a5d34de8575ffb04d289a987ff3053cf2c98ede445bea995e3830263", size = 363806, upload-time = "2025-08-14T17:11:18.29Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[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, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "sortedcontainers" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, -] - -[[package]] -name = "sqlalchemy" -version = "2.0.43" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d7/bc/d59b5d97d27229b0e009bd9098cd81af71c2fa5549c580a0a67b9bed0496/sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417", size = 9762949, upload-time = "2025-08-11T14:24:58.438Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/1c/a7260bd47a6fae7e03768bf66451437b36451143f36b285522b865987ced/sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3", size = 2130598, upload-time = "2025-08-11T15:51:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/8e/84/8a337454e82388283830b3586ad7847aa9c76fdd4f1df09cdd1f94591873/sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa", size = 2118415, upload-time = "2025-08-11T15:51:17.256Z" }, - { url = "https://files.pythonhosted.org/packages/cf/ff/22ab2328148492c4d71899d62a0e65370ea66c877aea017a244a35733685/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9", size = 3248707, upload-time = "2025-08-11T15:52:38.444Z" }, - { url = "https://files.pythonhosted.org/packages/dc/29/11ae2c2b981de60187f7cbc84277d9d21f101093d1b2e945c63774477aba/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f", size = 3253602, upload-time = "2025-08-11T15:56:37.348Z" }, - { url = "https://files.pythonhosted.org/packages/b8/61/987b6c23b12c56d2be451bc70900f67dd7d989d52b1ee64f239cf19aec69/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738", size = 3183248, upload-time = "2025-08-11T15:52:39.865Z" }, - { url = "https://files.pythonhosted.org/packages/86/85/29d216002d4593c2ce1c0ec2cec46dda77bfbcd221e24caa6e85eff53d89/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164", size = 3219363, upload-time = "2025-08-11T15:56:39.11Z" }, - { url = "https://files.pythonhosted.org/packages/b6/e4/bd78b01919c524f190b4905d47e7630bf4130b9f48fd971ae1c6225b6f6a/sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d", size = 2096718, upload-time = "2025-08-11T15:55:05.349Z" }, - { url = "https://files.pythonhosted.org/packages/ac/a5/ca2f07a2a201f9497de1928f787926613db6307992fe5cda97624eb07c2f/sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197", size = 2123200, upload-time = "2025-08-11T15:55:07.932Z" }, - { url = "https://files.pythonhosted.org/packages/b8/d9/13bdde6521f322861fab67473cec4b1cc8999f3871953531cf61945fad92/sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc", size = 1924759, upload-time = "2025-08-11T15:39:53.024Z" }, -] - -[[package]] -name = "sqlmodel" -version = "0.0.22" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "sqlalchemy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276, upload-time = "2024-08-31T09:43:22.358Z" }, -] - -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, -] - -[[package]] -name = "standard-imghdr" -version = "3.13.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/8d/ab2620fbe2e348483c9cb776c3b7b3cc407899291a041d7fa026469b7cd1/standard_imghdr-3.13.0.tar.gz", hash = "sha256:8d9c68058d882f6fc3542a8d39ef9ff94d2187dc90bd0c851e0902776b7b7a42", size = 5511, upload-time = "2024-10-30T16:01:36.412Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/cb/e1da7e340586a078404c7e4328bfefc930867ace8a9a55916fd220cf9547/standard_imghdr-3.13.0-py3-none-any.whl", hash = "sha256:30a1bff5465605bb496f842a6ac3cc1f2131bf3025b0da28d4877d6d4b7cc8e9", size = 4639, upload-time = "2024-10-30T16:01:13.829Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "tenacity" -version = "9.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, -] - -[[package]] -name = "tqdm" -version = "4.67.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, -] - -[[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "tzdata" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" }, - { url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" }, - { url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" }, - { url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" }, - { url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" }, - { url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" }, - { url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" }, - { url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" }, - { url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" }, - { url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" }, - { url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" }, - { url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" }, - { url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" }, - { url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" }, - { url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" }, - { url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" }, - { url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" }, - { url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" }, - { url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" }, - { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, - { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, - { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, - { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, - { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, - { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, - { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, - { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, - { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, - { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, - { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, - { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, - { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, - { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, - { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, - { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, - { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, - { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, -] - -[[package]] -name = "wcwidth" -version = "0.2.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "wheel" -version = "0.45.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, -] - -[[package]] -name = "wrapt" -version = "1.17.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, - { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, - { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, - { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, - { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, - { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, - { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, - { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, - { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, - { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, - { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, - { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, - { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, - { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, - { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, - { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, - { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, - { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, - { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, - { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, - { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, - { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, -] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -] diff --git a/scripts/ensure_rich.py b/scripts/ensure_rich.py deleted file mode 100644 index f2391198..00000000 --- a/scripts/ensure_rich.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python3 -"""Ensure rich is installed before running make_helper.py""" - -import subprocess -import sys - -try: - import rich -except ImportError: - print("Installing rich...") - subprocess.check_call(["uv", "pip", "install", "rich"]) diff --git a/scripts/generate-clients.sh b/scripts/generate-clients.sh new file mode 100755 index 00000000..fa877ef1 --- /dev/null +++ b/scripts/generate-clients.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Script to generate OpenAPI specs and Python client libraries + +set -e + +echo "Generating OpenAPI specs and client libraries..." + +# Function to generate client for a service +generate_client() { + local SERVICE=$1 + local PROJECT_DIR="projects/policyengine-api-${SERVICE}" + + echo "Processing ${SERVICE} API..." + + # Generate OpenAPI spec + echo " Generating OpenAPI spec..." + cd "${PROJECT_DIR}" + + # Install build dependencies if not already installed + uv sync --extra build + + uv run python -m policyengine_api_${SERVICE//-/_}.generate_openapi + + # Check if OpenAPI spec was created + if [ ! -f "artifacts/openapi.json" ]; then + echo " ❌ Failed to generate OpenAPI spec for ${SERVICE}" + return 1 + fi + + # Generate Python client + echo " Generating Python client..." + mkdir -p artifacts/clients + uv run openapi-python-client generate \ + --path artifacts/openapi.json \ + --output-path artifacts/clients/python \ + --overwrite + + # Update client package name + if [ -f "artifacts/clients/python/pyproject.toml" ]; then + sed -i.bak "s/^name = .*/name = \"policyengine_api_${SERVICE//-/_}_client\"/" artifacts/clients/python/pyproject.toml + rm artifacts/clients/python/pyproject.toml.bak + fi + + echo " ✅ Client generated for ${SERVICE}" + cd ../.. +} + +# Generate clients for both services +generate_client "full" +generate_client "simulation" + +echo "✅ All clients generated successfully!" +echo "" +echo "To use the clients in integration tests, run:" +echo " cd projects/policyengine-apis-integ" +echo " uv sync" \ No newline at end of file diff --git a/scripts/make_helper.py b/scripts/make_helper.py deleted file mode 100755 index cd56cff0..00000000 --- a/scripts/make_helper.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python3 -"""Helper script for prettier Makefile output using rich.""" - -import subprocess -import sys -import os -from pathlib import Path -from rich.console import Console -from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn -from rich.panel import Panel -from rich import box - -console = Console() - - -def get_indent_prefix(indent_level, is_last_line=False): - """Get the tree-style prefix for the current indent level.""" - if indent_level == 0: - return "" - - prefix = "" - for i in range(indent_level): - if i < indent_level - 1: - prefix += "│ " - else: - prefix += "├─" if not is_last_line else "└─" - return prefix - - -def get_continuing_prefix(indent_level): - """Get the continuing tree line prefix for multi-line output.""" - if indent_level == 0: - return "" - return "│ " * indent_level - - -def run_task(name, cmd, show_output=False, allow_failure=False): - """Run a task with a nice spinner and status indicator.""" - # Get current indent level from environment - indent_level = int(os.environ.get("MAKE_INDENT_LEVEL", "0")) - prefix = get_indent_prefix(indent_level) - continuing = get_continuing_prefix(indent_level) - - with Progress( - SpinnerColumn(), - TextColumn("[progress.description]{task.description}"), - console=console, - transient=not show_output, - ) as progress: - progress.add_task(f"{prefix}[cyan]{name}[/cyan]", total=None) - - # Pass incremented indent level to child processes - new_env = os.environ.copy() - new_env["MAKE_INDENT_LEVEL"] = str(indent_level + 1) - - if show_output: - result = subprocess.run(cmd, shell=True, text=True, env=new_env) - else: - result = subprocess.run( - cmd, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, # Combine stderr with stdout - text=True, - env=new_env, - ) - - if result.returncode == 0: - console.print(f"{prefix}[green]✓[/green] {name}") - if show_output and hasattr(result, "stdout") and result.stdout: - for line in result.stdout.strip().split("\n"): - console.print(f"{continuing} {line}", style="dim") - else: - if allow_failure: - console.print( - f"{prefix}[yellow]⚠[/yellow] {name} (non-critical failure)" - ) - else: - console.print(f"{prefix}[red]✗[/red] {name}") - # Show full output on error, not in a panel to avoid truncation - if hasattr(result, "stdout") and result.stdout: - console.print(f"{continuing}[red]Error output:[/red]") - for line in result.stdout.strip().split("\n"): - console.print(f"{continuing} {line}", style="red dim") - sys.exit(result.returncode) - - return result - - -def run_subtask(name, cmd): - """Run a subtask with indented output.""" - # Get current indent level from environment - indent_level = ( - int(os.environ.get("MAKE_INDENT_LEVEL", "0")) + 1 - ) # Subtasks get extra level - prefix = get_indent_prefix(indent_level) - continuing = get_continuing_prefix(indent_level) - - # Pass incremented indent level to child processes - new_env = os.environ.copy() - new_env["MAKE_INDENT_LEVEL"] = str(indent_level) - - result = subprocess.run( - cmd, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - env=new_env, - ) - - if result.returncode == 0: - console.print(f"{prefix}[green]✓[/green] {name}", style="dim") - else: - console.print(f"{prefix}[red]✗[/red] {name}", style="dim") - # Show full output including stdout and stderr - if result.stdout: - console.print(f"{continuing}[red]Error details:[/red]") - for line in result.stdout.strip().split("\n"): - console.print(f"{continuing} {line}", style="red dim") - sys.exit(result.returncode) # Exit on subtask failure - return True - - -def section_header(title): - """Print a nice section header.""" - # Get current indent level from environment - indent_level = int(os.environ.get("MAKE_INDENT_LEVEL", "0")) - prefix = get_continuing_prefix(indent_level) - - console.print() - if indent_level > 0: - # For nested sections, use a simpler format with tree line - console.print(f"{prefix}[bold cyan]── {title} ──[/bold cyan]") - else: - # Top-level sections get the full rule - console.rule(f"[bold cyan]{title}[/bold cyan]", style="cyan") - - -def completion_message(message, success=True): - """Print a completion message.""" - style = "green" if success else "red" - icon = "✓" if success else "✗" - console.print() - console.print( - Panel( - f"[{style}]{icon}[/{style}] {message}", - border_style=style, - box=box.ROUNDED, - ) - ) - - -def list_items(items, title=None): - """Print a list of items.""" - if title: - console.print(f"\n[bold]{title}:[/bold]") - for item in items: - console.print(f" • {item}") - - -if __name__ == "__main__": - if len(sys.argv) < 2: - console.print("[red]Usage: make_helper.py [args...]") - sys.exit(1) - - command = sys.argv[1] - - if command == "task": - # Run a single task - if len(sys.argv) < 4: - console.print("[red]Usage: make_helper.py task ") - sys.exit(1) - name = sys.argv[2] - cmd = " ".join(sys.argv[3:]) - run_task(name, cmd) - - elif command == "subtask": - # Run a subtask (indented) - if len(sys.argv) < 4: - console.print("[red]Usage: make_helper.py subtask ") - sys.exit(1) - name = sys.argv[2] - cmd = " ".join(sys.argv[3:]) - run_subtask(name, cmd) - - elif command == "section": - # Print a section header - if len(sys.argv) < 3: - console.print("[red]Usage: make_helper.py section ") - sys.exit(1) - title = " ".join(sys.argv[2:]) - section_header(title) - - elif command == "complete": - # Print completion message - if len(sys.argv) < 3: - console.print("[red]Usage: make_helper.py complete <message> [success]") - sys.exit(1) - message = sys.argv[2] - success = sys.argv[3].lower() == "true" if len(sys.argv) > 3 else True - completion_message(message, success) - - elif command == "list": - # List items - if len(sys.argv) < 3: - console.print("[red]Usage: make_helper.py list <item1> <item2> ...") - sys.exit(1) - items = sys.argv[2:] - list_items(items) - - elif command == "stream": - # Run a command with streaming output - if len(sys.argv) < 4: - console.print( - "[red]Usage: make_helper.py stream <name> <command> [indent_level]" - ) - sys.exit(1) - name = sys.argv[2] - - # Check for indent level from environment or arguments - env_indent = int(os.environ.get("MAKE_INDENT_LEVEL", "0")) - - # Check if there's an indent level specified in arguments - if len(sys.argv) > 4 and sys.argv[-1].isdigit(): - indent_level = int(sys.argv[-1]) - cmd = " ".join(sys.argv[3:-1]) - else: - indent_level = env_indent - cmd = " ".join(sys.argv[3:]) - - # Apply tree-style prefixes - prefix = get_indent_prefix(indent_level) - # For stream output, we want to show a tree line connecting to the parent - # Even at level 0, we add a visual indicator - if indent_level == 0: - continuing = "│ " # Always show a tree line for streamed output - else: - continuing = get_continuing_prefix(indent_level) - - console.print(f"{prefix}[cyan]▶[/cyan] {name}") - - # Set environment variable for nested calls - new_env = os.environ.copy() - new_env["MAKE_INDENT_LEVEL"] = str(indent_level + 1) - - # Always use Popen to process output line by line with proper indentation - process = subprocess.Popen( - cmd, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - bufsize=1, - universal_newlines=True, - env=new_env, - ) - - # Process output line by line with tree continuation - for line in iter(process.stdout.readline, ""): - if line: - # Strip trailing newline but keep other whitespace - line = line.rstrip("\n\r") - if line: # Only print non-empty lines - # Handle special cases like Docker's progress output - if line.startswith("#"): - # Docker build steps - add special formatting - console.print(f"{continuing}[dim] {line}[/dim]") - elif line.startswith("=>") or line.startswith(" =>"): - # Docker layer output - console.print(f"{continuing}[cyan] {line}[/cyan]") - else: - console.print(f"{continuing} {line}") - - process.wait() - result_code = process.returncode - - if result_code != 0: - console.print(f"{prefix}[red]✗[/red] {name} failed") - sys.exit(result_code) - - elif command == "progress": - # Run command with progress bar for multiple subdirectories - if len(sys.argv) < 4: - console.print("[red]Usage: make_helper.py progress <title> <dirs...>") - sys.exit(1) - title = sys.argv[2] - dirs = sys.argv[3:] - - with Progress( - TextColumn("[progress.description]{task.description}"), - BarColumn(), - TextColumn("[progress.percentage]{task.percentage:>3.0f}%"), - console=console, - ) as progress: - task = progress.add_task(f"[cyan]{title}[/cyan]", total=len(dirs)) - - failed = [] - for dir_name in dirs: - dir_base = Path(dir_name).name - progress.update(task, description=f"[cyan]{title}[/cyan] - {dir_base}") - - # Extract the actual make command from the directory - make_cmd = f"$(MAKE) -C {dir_name} {title.lower().replace(' ', '-')}" - result = subprocess.run( - make_cmd, shell=True, capture_output=True, text=True - ) - - if result.returncode != 0: - failed.append(dir_base) - - progress.advance(task) - - if failed: - console.print(f"\n[red]Failed in: {', '.join(failed)}[/red]") - sys.exit(1) - else: - console.print(f"\n[green]✓[/green] {title} completed successfully") - - else: - console.print(f"[red]Unknown command: {command}") - sys.exit(1) diff --git a/scripts/publish-clients.sh b/scripts/publish-clients.sh new file mode 100755 index 00000000..2698f84c --- /dev/null +++ b/scripts/publish-clients.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Script to build and publish API client packages to PyPI + +set -e + +echo "Publishing API client packages to PyPI..." + +# Function to publish a client package +publish_client() { + local SERVICE=$1 + local CLIENT_DIR="projects/policyengine-api-${SERVICE}/artifacts/clients/python" + + echo "Publishing ${SERVICE} API client..." + + # Check if client exists + if [ ! -d "${CLIENT_DIR}" ]; then + echo " ❌ Client directory not found: ${CLIENT_DIR}" + echo " Running client generation first..." + ./scripts/generate-clients.sh + fi + + cd "${CLIENT_DIR}" + + # Update version based on date and commit SHA + # Format: 0.YYYYMMDD.SHORT_SHA (e.g., 0.20240820.abc1234) + if [ -n "${GITHUB_SHA}" ]; then + # In GitHub Actions + SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7) + else + # Local development + SHORT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "dev") + fi + DATE=$(date +%Y%m%d) + NEW_VERSION="0.${DATE}.${SHORT_SHA}" + + # Update version in pyproject.toml + echo " Updating version to: ${NEW_VERSION}" + sed -i.bak "s/^version = .*/version = \"${NEW_VERSION}\"/" pyproject.toml + rm pyproject.toml.bak + + # Build the package + echo " Building package..." + uv build + + # Publish to PyPI + echo " Publishing to PyPI..." + uv publish --token "${PYPI_TOKEN}" + + echo " ✅ Successfully published policyengine_api_${SERVICE//-/_}_client version ${NEW_VERSION}" + + cd ../../../../../ +} + +# Check if PYPI_TOKEN is set +if [ -z "${PYPI_TOKEN}" ]; then + echo "❌ PYPI_TOKEN environment variable is not set" + exit 1 +fi + +# Publish both clients +publish_client "full" +publish_client "simulation" + +echo "✅ All clients published successfully!" \ No newline at end of file diff --git a/scripts/test-integration-local.sh b/scripts/test-integration-local.sh new file mode 100755 index 00000000..52a3962f --- /dev/null +++ b/scripts/test-integration-local.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Script to run integration tests against local docker-compose services + +set -e + +echo "Starting services with docker-compose..." +docker-compose -f deployment/docker-compose.yml up -d + +echo "Waiting for services to be ready..." +# Wait for services to start up +sleep 5 + +# Function to check if a service is responding +check_service() { + local SERVICE_NAME=$1 + local PORT=$2 + local MAX_ATTEMPTS=30 + local ATTEMPT=0 + + echo -n "Checking $SERVICE_NAME on port $PORT..." + while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do + if curl -s -o /dev/null -w "%{http_code}" "http://localhost:$PORT/ping/alive" | grep -q "200"; then + echo " ✅ Ready!" + return 0 + fi + ATTEMPT=$((ATTEMPT + 1)) + echo -n "." + sleep 2 + done + echo " ❌ Failed to connect after $MAX_ATTEMPTS attempts" + return 1 +} + +# Check each service +check_service "api-full" 8081 +check_service "api-simulation" 8082 +check_service "api-tagger" 8083 + +echo "" +echo "Running integration tests (excluding GCP workflow tests)..." +cd projects/policyengine-apis-integ +uv sync --extra test +uv run pytest tests/ -v -m "not requires_gcp" +cd ../.. + +echo "" +echo "Stopping services..." +docker-compose -f deployment/docker-compose.yml down + +echo "✅ Integration tests completed!" \ No newline at end of file diff --git a/server_common.deploy.mk b/server_common.deploy.mk deleted file mode 100644 index b4baef1d..00000000 --- a/server_common.deploy.mk +++ /dev/null @@ -1,4 +0,0 @@ -## pull the tag and region from the tf vars used by the github actions workflow -TAG=${TF_VAR_container_tag} -REGION=${TF_VAR_region} -include ../../server_common.mk diff --git a/server_common.local.mk b/server_common.local.mk deleted file mode 100644 index 70489cdb..00000000 --- a/server_common.local.mk +++ /dev/null @@ -1 +0,0 @@ -include ../../server_common.mk diff --git a/server_common.mk b/server_common.mk deleted file mode 100644 index 979cd154..00000000 --- a/server_common.mk +++ /dev/null @@ -1,18 +0,0 @@ -include ../../common.mk - -TAG?=desktop -REPO?=api-v2 -REGION?=us-central1 -ifdef LOG_DIR - BUILD_ARGS=--gcs-log-dir ${LOG_DIR} -endif -PROJECT_ID?=PROJECT_ID_NOT_SPECIFIED -WORKER_COUNT?=1 - -deploy: - echo "Building ${SERVICE_NAME} docker image" - cd ../../ && gcloud builds submit --region=${REGION} --substitutions=_IMAGE_TAG=${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO}/${SERVICE_NAME}:${TAG},_SERVICE_NAME=${SERVICE_NAME},_MODULE_NAME=${MODULE_NAME},_WORKER_COUNT=${WORKER_COUNT} ${BUILD_ARGS} - -dev: - echo "Running ${SERVICE_NAME} dev instance" - cd src && uv run uvicorn ${MODULE_NAME}:app --reload --port ${DEV_PORT} --workers ${WORKER_COUNT} diff --git a/terraform/infra-policyengine-api/Makefile b/terraform/infra-policyengine-api/Makefile deleted file mode 100644 index e67f2ba2..00000000 --- a/terraform/infra-policyengine-api/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# For github action deployes we use environment variables to configure terraform -# on desktop we use apply files generated either by the infra-policyengine-api bootstrap -# or manual user config -REPO_URL := $(shell git remote get-url origin | sed 's/\.git$$//' | sed 's/git@github.com:/https:\/\/github.com\//') -COMMIT_SHA := $(shell git rev-parse HEAD) -COMMIT_URL := $(REPO_URL)/commit/$(COMMIT_SHA) - -# get the project ID --include ../.bootstrap_settings/project.env -TAG?=desktop -REPO?=api-v2 -REGION?=us-central1 - - -#we have to find the sha of the latest images because terraform doesn't know -#that a label got a new sha between deployments -deploy: .terraform - @echo "Attempting to get the latest docker images with the '${TAG}' tag" - $(eval FULL_SHA := $(shell gcloud artifacts docker images describe $(REGION)-docker.pkg.dev/$(PROJECT_ID)/$(REPO)/policyengine-api-full:$(TAG) --format='value(image_summary.digest)')) - $(eval SIM_SHA := $(shell gcloud artifacts docker images describe $(REGION)-docker.pkg.dev/$(PROJECT_ID)/$(REPO)/policyengine-api-simulation:$(TAG) --format='value(image_summary.digest)')) - $(eval TAGGER_SHA := $(shell gcloud artifacts docker images describe $(REGION)-docker.pkg.dev/$(PROJECT_ID)/$(REPO)/policyengine-api-tagger:$(TAG) --format='value(image_summary.digest)')) - @echo "Latest Full API SHA: ${FULL_SHA}" - @echo "Latest Simulation API SHA: ${SIM_SHA}" - @echo "Running terraform apply with ../.bootstrap_settings/apply.tfvars" - terraform apply -var-file ../.bootstrap_settings/apply.tfvars -var "full_container_tag=${TAG}@${FULL_SHA}" -var "simulation_container_tag=${TAG}@${SIM_SHA}" -var "tagger_container_tag=${TAG}@${TAGGER_SHA}" -var "commit_url=${COMMIT_URL}" -var "policyengine-us-package-version=desktop" -var "policyengine-uk-package-version=desktop" - -attach: .terraform - @echo "attached" - -detach: - rm -rf .terraform - -destroy: - terraform plan -destroy -var-file ../.bootstrap_settings/apply.tfvars --var "full_container_tag=IGNORED" -var "simulation_container_tag=IGNORED" -var "tagger_container_tag=IGNORE" -var "commit_url=IGNORE" -var "policyengine-us-package-version=IGNORED" -var "policyengine-uk-package-version=IGNORED" - @echo 'please confirm this IS NOT a production project and then run terraform destroy -var-file ../.bootstrap_settings/apply.tfvars --var "full_container_tag=IGNORED" -var "simulation_container_tag=IGNORED" -var "tagger_container_tag=IGNORE" -var "commit_url=IGNORE" -var "policyengine-us-package-version=IGNORED" -var "policyengine-uk-package-version=IGNORED"' - -.terraform: ../.bootstrap_settings/backend.tfvars - @echo "Initializing terraform" - terraform init -backend-config ../.bootstrap_settings/backend.tfvars - -bootstrap_beta: - cd ../infra-policyengine-api && make bootstrap_beta diff --git a/terraform/infra-policyengine-api/Makefile.deploy b/terraform/infra-policyengine-api/Makefile.deploy deleted file mode 100644 index fd81f880..00000000 --- a/terraform/infra-policyengine-api/Makefile.deploy +++ /dev/null @@ -1,23 +0,0 @@ -REPO_URL := $(shell git remote get-url origin | sed 's/\.git$$//' | sed 's/git@github.com:/https:\/\/github.com\//') -COMMIT_SHA := $(shell git rev-parse HEAD) -COMMIT_URL := $(REPO_URL)/commit/$(COMMIT_SHA) -SCRIPT_DIR := $(dir $(lastword $(MAKEFILE_LIST))) -US_COUNTRY_PACKAGE_VERSION := $(shell ../../projects/policyengine-api-simulation/dump_package_version.sh policyengine-us) -UK_COUNTRY_PACKAGE_VERSION := $(shell ../../projects/policyengine-api-simulation/dump_package_version.sh policyengine-uk) -METADATA_BUCKET = $(shell terraform output -raw metadata_bucket_name) - -plan-deploy: .terraform - terraform plan -input=false - -state: .terraform - terraform output -json - -deploy: .terraform - terraform apply -input=false -auto-approve -var "commit_url=${COMMIT_URL}" -var "policyengine-us-package-version=${US_COUNTRY_PACKAGE_VERSION}" -var "policyengine-uk-package-version=${UK_COUNTRY_PACKAGE_VERSION}" - terraform output -json > terraform_output.json - terraform output -json release_metadata | gsutil cp - gs://$(METADATA_BUCKET)/live.json - terraform output -json release_metadata | gsutil cp - gs://$(METADATA_BUCKET)/us.$(US_COUNTRY_PACKAGE_VERSION).json - terraform output -json release_metadata | gsutil cp - gs://$(METADATA_BUCKET)/uk.$(UK_COUNTRY_PACKAGE_VERSION).json - -.terraform: - terraform init -backend-config="bucket=${TF_BACKEND_bucket}" diff --git a/terraform/infra-policyengine-api/backend.example.tfvars b/terraform/infra-policyengine-api/backend.example.tfvars deleted file mode 100644 index 8dd0da82..00000000 --- a/terraform/infra-policyengine-api/backend.example.tfvars +++ /dev/null @@ -1,2 +0,0 @@ -bucket = "your terraform storage bucket" -path = "terraform/desktop/policyengine-api" \ No newline at end of file diff --git a/terraform/infra-policyengine-api/backend.tf b/terraform/infra-policyengine-api/backend.tf deleted file mode 100644 index 242fd8b5..00000000 --- a/terraform/infra-policyengine-api/backend.tf +++ /dev/null @@ -1,6 +0,0 @@ -terraform { - backend "gcs" { - bucket = "" - prefix = "terraform/desktop/policyengine-api" - } -} \ No newline at end of file diff --git a/terraform/project-policyengine-api/Makefile b/terraform/project-policyengine-api/Makefile deleted file mode 100644 index 15808c50..00000000 --- a/terraform/project-policyengine-api/Makefile +++ /dev/null @@ -1,27 +0,0 @@ - -bootstrap: - scripts/bootstrap.sh desktop - -attach: - scripts/attach.sh - terraform init - -detach: - rm -f backend.tf - rm -rf ../.bootstrap_settings - rm -rf .terraform - rm -rf terraform.tfstate* - -bootstrap_beta: - scripts/bootstrap.sh beta - -bootstrap_prod: - scripts/bootstrap.sh prod - -deploy: - @echo "Attempting to deploy project using bootstrap settings in ../.bootstrap_settings/apply.tfvars" - terraform apply --var-file=../.bootstrap_settings/apply.tfvars - -destroy: - terraform plan -destroy --var-file=../.bootstrap_settings/apply.tfvars - @echo "In order to _actually_ destroy the resources please MAKE SURE THIS IS NOT A PRODUCTION ACCOUNT and run: terraform destroy --var-file=../.bootstrap_settings/apply.tfvars" diff --git a/terraform/project-policyengine-api/Makefile.deploy b/terraform/project-policyengine-api/Makefile.deploy deleted file mode 100644 index 97139202..00000000 --- a/terraform/project-policyengine-api/Makefile.deploy +++ /dev/null @@ -1,13 +0,0 @@ -deploy: .terraform - terraform apply -input=false -auto-approve - -plan-deploy: .terraform - terraform plan - -backend.tf: - cp backend.example_tf backend.tf - -#Apply supports setting values with TF_VAR, but TF_BACKEND_ is not, as of writing, supported by -#terraform -.terraform: backend.tf - terraform init -backend-config="bucket=${TF_BACKEND_bucket}" diff --git a/terraform/project-policyengine-api/backend.example_tf b/terraform/project-policyengine-api/backend.example_tf deleted file mode 100644 index ba7820ad..00000000 --- a/terraform/project-policyengine-api/backend.example_tf +++ /dev/null @@ -1,6 +0,0 @@ -terraform { - backend "gcs" { - bucket = "YOUR_BUCKET" - prefix = "terraform/project" - } -} \ No newline at end of file