agent-starter-pack 0.6.4__py3-none-any.whl → 0.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {agent_starter_pack-0.6.4.dist-info → agent_starter_pack-0.7.1.dist-info}/METADATA +15 -12
  2. {agent_starter_pack-0.6.4.dist-info → agent_starter_pack-0.7.1.dist-info}/RECORD +34 -31
  3. agents/adk_gemini_fullstack/app/agent.py +62 -8
  4. llm.txt +296 -0
  5. src/base_template/.gitignore +1 -1
  6. src/base_template/GEMINI.md +5 -0
  7. src/base_template/Makefile +20 -5
  8. src/base_template/README.md +3 -0
  9. src/base_template/deployment/cd/deploy-to-prod.yaml +3 -3
  10. src/base_template/deployment/cd/staging.yaml +4 -4
  11. src/base_template/deployment/ci/pr_checks.yaml +1 -1
  12. src/base_template/pyproject.toml +2 -2
  13. src/cli/utils/cicd.py +4 -1
  14. src/cli/utils/template.py +22 -18
  15. src/data_ingestion/uv.lock +97 -0
  16. src/frontends/adk_gemini_fullstack/frontend/package-lock.json +276 -0
  17. src/frontends/adk_gemini_fullstack/frontend/package.json +1 -0
  18. src/frontends/adk_gemini_fullstack/frontend/src/components/ChatMessagesView.tsx +5 -4
  19. src/frontends/adk_gemini_fullstack/frontend/vite.config.ts +4 -0
  20. src/resources/docs/adk-cheatsheet.md +1224 -0
  21. src/resources/locks/uv-adk_base-agent_engine.lock +14 -13
  22. src/resources/locks/uv-adk_base-cloud_run.lock +14 -13
  23. src/resources/locks/uv-adk_gemini_fullstack-agent_engine.lock +14 -13
  24. src/resources/locks/uv-adk_gemini_fullstack-cloud_run.lock +14 -13
  25. src/resources/locks/uv-agentic_rag-agent_engine.lock +78 -83
  26. src/resources/locks/uv-agentic_rag-cloud_run.lock +110 -119
  27. src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +130 -135
  28. src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +163 -172
  29. src/resources/locks/uv-langgraph_base_react-agent_engine.lock +87 -92
  30. src/resources/locks/uv-langgraph_base_react-cloud_run.lock +119 -128
  31. src/resources/locks/uv-live_api-cloud_run.lock +98 -107
  32. {agent_starter_pack-0.6.4.dist-info → agent_starter_pack-0.7.1.dist-info}/WHEEL +0 -0
  33. {agent_starter_pack-0.6.4.dist-info → agent_starter_pack-0.7.1.dist-info}/entry_points.txt +0 -0
  34. {agent_starter_pack-0.6.4.dist-info → agent_starter_pack-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,12 @@
1
+ # Install dependencies using uv package manager
1
2
  install:
2
3
  @command -v uv >/dev/null 2>&1 || { echo "uv is not installed. Installing uv..."; curl -LsSf https://astral.sh/uv/0.6.12/install.sh | sh; source $HOME/.local/bin/env; }
3
- uv sync --dev{% if cookiecutter.agent_name != 'live_api' and "adk" not in cookiecutter.tags %} --extra streamlit{%- endif %} --extra jupyter --frozen{% if cookiecutter.agent_name == 'live_api' %} && npm --prefix frontend install{%- endif %}
4
+ uv sync --dev{% if cookiecutter.agent_name != 'live_api' and "adk" not in cookiecutter.tags %} --extra streamlit{%- endif %} --extra jupyter{% if cookiecutter.agent_name == 'live_api' %} && npm --prefix frontend install{%- endif %}
4
5
  {%- if cookiecutter.settings.get("commands", {}).get("override", {}).get("install") %} && {{cookiecutter.settings.get("commands", {}).get("override", {}).get("install")}}{%- endif %}
5
6
  {%- if cookiecutter.settings.get("commands", {}).get("extra", {}) %}
6
7
  {%- for cmd_name, cmd_value in cookiecutter.settings.get("commands", {}).get("extra", {}).items() %}
7
8
 
9
+ # {{ cmd_value.get("description") }}
8
10
  {{ cmd_name }}:
9
11
  {%- if cmd_value is mapping %}
10
12
  {%- if cmd_value.command is mapping and cookiecutter.deployment_target in cmd_value.command %}
@@ -17,6 +19,7 @@ install:
17
19
  {%- endif %}
18
20
  {%- endfor %}{%- endif %}
19
21
 
22
+ # Launch local dev playground
20
23
  playground:
21
24
  {%- if cookiecutter.settings.get("commands", {}).get("override", {}).get("playground") %}
22
25
  {{cookiecutter.settings.get("commands", {}).get("override", {}).get("playground")}}
@@ -44,10 +47,14 @@ playground:
44
47
  {%- endif %}
45
48
  {%- endif %}
46
49
 
50
+ # Deploy the agent remotely
51
+ {%- if cookiecutter.deployment_target == 'cloud_run' %}
52
+ # Usage: make backend [IAP=true] [PORT=8080] - Set IAP=true to enable Identity-Aware Proxy, PORT to specify container port
53
+ {%- endif %}
47
54
  backend:
48
55
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
49
56
  PROJECT_ID=$$(gcloud config get-value project) && \
50
- gcloud run deploy {{cookiecutter.project_name}} \
57
+ gcloud beta run deploy {{cookiecutter.project_name}} \
51
58
  --source . \
52
59
  --memory "4Gi" \
53
60
  --project $$PROJECT_ID \
@@ -55,31 +62,37 @@ backend:
55
62
  --no-allow-unauthenticated \
56
63
  --labels "created-by=adk" \
57
64
  --set-env-vars \
58
- "COMMIT_SHA=$(shell git rev-parse HEAD){%- if cookiecutter.data_ingestion %}{%- if cookiecutter.datastore_type == "vertex_ai_search" %},DATA_STORE_ID={{cookiecutter.project_name}}-datastore,DATA_STORE_REGION=us{%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %},VECTOR_SEARCH_INDEX={{cookiecutter.project_name}}-vector-search,VECTOR_SEARCH_INDEX_ENDPOINT={{cookiecutter.project_name}}-vector-search-endpoint,VECTOR_SEARCH_BUCKET=$$PROJECT_ID-{{cookiecutter.project_name}}-vs{%- endif %}{%- endif %}"
65
+ "COMMIT_SHA=$(shell git rev-parse HEAD){%- if cookiecutter.data_ingestion %}{%- if cookiecutter.datastore_type == "vertex_ai_search" %},DATA_STORE_ID={{cookiecutter.project_name}}-datastore,DATA_STORE_REGION=us{%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %},VECTOR_SEARCH_INDEX={{cookiecutter.project_name}}-vector-search,VECTOR_SEARCH_INDEX_ENDPOINT={{cookiecutter.project_name}}-vector-search-endpoint,VECTOR_SEARCH_BUCKET=$$PROJECT_ID-{{cookiecutter.project_name}}-vs{%- endif %}{%- endif %}" \
66
+ $(if $(IAP),--iap) \
67
+ $(if $(PORT),--port=$(PORT))
59
68
  {%- elif cookiecutter.deployment_target == 'agent_engine' %}
60
69
  # Export dependencies to requirements file using uv export.
61
- uv export --no-hashes --no-header --no-dev --no-emit-project --no-annotate --frozen > .requirements.txt 2>/dev/null || \
62
- uv export --no-hashes --no-header --no-dev --no-emit-project --frozen > .requirements.txt && uv run app/agent_engine_app.py
70
+ uv export --no-hashes --no-header --no-dev --no-emit-project --no-annotate > .requirements.txt 2>/dev/null || \
71
+ uv export --no-hashes --no-header --no-dev --no-emit-project > .requirements.txt && uv run app/agent_engine_app.py
63
72
  {%- endif %}
64
73
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
65
74
 
75
+ # Launch local development server with hot-reload
66
76
  local-backend:
67
77
  uv run uvicorn app.server:app --host 0.0.0.0 --port 8000 --reload
68
78
  {%- endif %}
69
79
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
70
80
  {%- if cookiecutter.agent_name == 'live_api' %}
71
81
 
82
+ # Start the frontend UI for development
72
83
  ui:
73
84
  PORT=8501 npm --prefix frontend start
74
85
  {%- endif %}
75
86
  {%- endif %}
76
87
 
88
+ # Set up development environment resources using Terraform
77
89
  setup-dev-env:
78
90
  PROJECT_ID=$$(gcloud config get-value project) && \
79
91
  (cd deployment/terraform/dev && terraform init && terraform apply --var-file vars/env.tfvars --var dev_project_id=$$PROJECT_ID --auto-approve)
80
92
 
81
93
  {%- if cookiecutter.data_ingestion %}
82
94
 
95
+ # Run the data ingestion pipeline for RAG capabilities
83
96
  data-ingestion:
84
97
  PROJECT_ID=$$(gcloud config get-value project) && \
85
98
  (cd data_ingestion && uv run data_ingestion_pipeline/submit_pipeline.py \
@@ -98,9 +111,11 @@ data-ingestion:
98
111
  --pipeline-name="data-ingestion-pipeline")
99
112
  {%- endif %}
100
113
 
114
+ # Run unit and integration tests
101
115
  test:
102
116
  uv run pytest tests/unit && uv run pytest tests/integration
103
117
 
118
+ # Run code quality checks (codespell, ruff, mypy)
104
119
  lint:
105
120
  uv run codespell
106
121
  uv run ruff check . --diff
@@ -21,6 +21,7 @@ This project is organized as follows:
21
21
  ├── notebooks/ # Jupyter notebooks for prototyping and evaluation
22
22
  ├── tests/ # Unit, integration, and load tests
23
23
  ├── Makefile # Makefile for common commands
24
+ ├── GEMINI.md # AI-assisted development guide
24
25
  └── pyproject.toml # Project dependencies and configuration
25
26
  ```
26
27
 
@@ -160,6 +161,8 @@ This template follows a "bring your own agent" approach - you focus on your busi
160
161
  3. **Test:** Explore your agent functionality using the Streamlit playground with `make playground`. The playground offers features like chat history, user feedback, and various input types, and automatically reloads your agent on code changes.
161
162
  4. **Deploy:** Set up and initiate the CI/CD pipelines, customizing tests as necessary. Refer to the [deployment section](#deployment) for comprehensive instructions. For streamlined infrastructure deployment, simply run `uvx agent-starter-pack setup-cicd`. Check out the [`agent-starter-pack setup-cicd` CLI command](https://googlecloudplatform.github.io/agent-starter-pack/cli/setup_cicd.html). Currently only supporting Github.
162
163
  5. **Monitor:** Track performance and gather insights using Cloud Logging, Tracing, and the Looker Studio dashboard to iterate on your application.
164
+
165
+ The project includes a `GEMINI.md` file that provides context for AI tools like Gemini CLI when asking questions about your template.
163
166
  {% endif %}
164
167
 
165
168
  ## Deployment
@@ -21,7 +21,7 @@ steps:
21
21
  - -c
22
22
  - |
23
23
  cd data_ingestion && pip install uv==0.6.12 --user && cd data_ingestion_pipeline && \
24
- uv sync --frozen && uv run python submit_pipeline.py
24
+ uv sync --locked && uv run python submit_pipeline.py
25
25
  env:
26
26
  - "PIPELINE_ROOT=${_PIPELINE_GCS_ROOT}"
27
27
  - "REGION=${_REGION}"
@@ -78,7 +78,7 @@ steps:
78
78
  args:
79
79
  - "-c"
80
80
  - |
81
- pip install uv==0.6.12 --user && uv sync --frozen
81
+ pip install uv==0.6.12 --user && uv sync --locked
82
82
  env:
83
83
  - 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
84
84
 
@@ -88,7 +88,7 @@ steps:
88
88
  args:
89
89
  - "-c"
90
90
  - |
91
- uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --frozen > .requirements.txt
91
+ uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --locked > .requirements.txt
92
92
  uv run app/agent_engine_app.py \
93
93
  --project ${_PROD_PROJECT_ID} \
94
94
  --location ${_REGION} \
@@ -21,7 +21,7 @@ steps:
21
21
  - -c
22
22
  - |
23
23
  cd data_ingestion && pip install uv==0.6.12 --user && cd data_ingestion_pipeline && \
24
- uv sync --frozen && uv run python submit_pipeline.py
24
+ uv sync --locked && uv run python submit_pipeline.py
25
25
  env:
26
26
  - "PIPELINE_ROOT=${_PIPELINE_GCS_ROOT}"
27
27
  - "REGION=${_REGION}"
@@ -111,7 +111,7 @@ steps:
111
111
  args:
112
112
  - "-c"
113
113
  - |
114
- pip install uv==0.6.12 --user && uv sync --frozen
114
+ pip install uv==0.6.12 --user && uv sync --locked
115
115
  env:
116
116
  - 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
117
117
 
@@ -121,7 +121,7 @@ steps:
121
121
  args:
122
122
  - "-c"
123
123
  - |
124
- uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --frozen > .requirements.txt
124
+ uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --locked > .requirements.txt
125
125
  uv run app/agent_engine_app.py \
126
126
  --project ${_STAGING_PROJECT_ID} \
127
127
  --location ${_REGION} \
@@ -149,7 +149,7 @@ steps:
149
149
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
150
150
  export _ID_TOKEN=$(cat id_token.txt)
151
151
  export _STAGING_URL=$(cat staging_url.txt)
152
- pip install uv==0.6.12 --user && uv sync --frozen
152
+ pip install uv==0.6.12 --user && uv sync --locked
153
153
  {%- elif cookiecutter.deployment_target == 'agent_engine' %}
154
154
  export _AUTH_TOKEN=$(cat auth_token.txt)
155
155
  {%- endif %}
@@ -20,7 +20,7 @@ steps:
20
20
  args:
21
21
  - "-c"
22
22
  - |
23
- pip install uv==0.6.12 --user && uv sync --frozen
23
+ pip install uv==0.6.12 --user && uv sync --locked
24
24
  env:
25
25
  - 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
26
26
 
@@ -16,11 +16,11 @@ dependencies = [
16
16
  {%- endif %}
17
17
  "google-cloud-logging~=3.11.4",
18
18
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
19
- "google-cloud-aiplatform[evaluation]~=1.95.1",
19
+ "google-cloud-aiplatform[evaluation]~=1.99.0",
20
20
  "fastapi~=0.115.8",
21
21
  "uvicorn~=0.34.0"
22
22
  {%- elif cookiecutter.deployment_target == 'agent_engine' %}
23
- "google-cloud-aiplatform[evaluation,agent-engines]~=1.95.1"
23
+ "google-cloud-aiplatform[evaluation,agent-engines]~=1.99.0"
24
24
  {%- endif %}
25
25
  ]
26
26
  {% if cookiecutter.deployment_target == 'cloud_run' %}
src/cli/utils/cicd.py CHANGED
@@ -212,7 +212,10 @@ def create_github_connection(
212
212
  return secret_id, app_installation_id
213
213
  elif status == "PENDING_USER_OAUTH" or status == "PENDING_INSTALL_APP":
214
214
  if attempt < max_retries - 1: # Don't print waiting on last attempt
215
- console.print("⏳ Waiting for GitHub authorization...")
215
+ console.print("⏳ Waiting for authorization...")
216
+ print(
217
+ f"Console: https://console.cloud.google.com/cloud-build/repositories?project={project_id}"
218
+ )
216
219
  # Extract and print the action URI for user authentication
217
220
  try:
218
221
  action_uri = (
src/cli/utils/template.py CHANGED
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import json
15
16
  import logging
16
17
  import os
17
18
  import pathlib
@@ -23,7 +24,7 @@ from typing import Any
23
24
  import yaml
24
25
  from cookiecutter.main import cookiecutter
25
26
  from rich.console import Console
26
- from rich.prompt import Prompt
27
+ from rich.prompt import IntPrompt, Prompt
27
28
 
28
29
  from src.cli.utils.version import get_current_version
29
30
 
@@ -197,8 +198,6 @@ def prompt_deployment_target(agent_name: str) -> str:
197
198
  description = info.get("description", "")
198
199
  console.print(f"{idx}. [bold]{display_name}[/] - [dim]{description}[/]")
199
200
 
200
- from rich.prompt import IntPrompt
201
-
202
201
  choice = IntPrompt.ask(
203
202
  "\nEnter the number of your deployment target choice",
204
203
  default=1,
@@ -468,15 +467,6 @@ def process_template(
468
467
  agent_folder, project_folder, agent_name, overwrite=True
469
468
  )
470
469
 
471
- # Copy agent README.md if it exists
472
- agent_readme = agent_path / "README.md"
473
- if agent_readme.exists():
474
- agent_readme_dest = project_template / "agent_README.md"
475
- shutil.copy2(agent_readme, agent_readme_dest)
476
- logging.debug(
477
- f"Copied agent README from {agent_readme} to {agent_readme_dest}"
478
- )
479
-
480
470
  # Load and validate template config first
481
471
  template_path = pathlib.Path(template_dir)
482
472
  config = load_template_config(template_path)
@@ -510,6 +500,22 @@ def process_template(
510
500
  frontend_type = settings.get("frontend_type", DEFAULT_FRONTEND)
511
501
  tags = settings.get("tags", ["None"])
512
502
 
503
+ # Load adk-cheatsheet.md and llm.txt for injection
504
+ adk_cheatsheet_path = (
505
+ pathlib.Path(__file__).parent.parent.parent
506
+ / "resources"
507
+ / "docs"
508
+ / "adk-cheatsheet.md"
509
+ )
510
+ with open(adk_cheatsheet_path) as f:
511
+ adk_cheatsheet_content = f.read()
512
+
513
+ llm_txt_path = (
514
+ pathlib.Path(__file__).parent.parent.parent.parent / "llm.txt"
515
+ )
516
+ with open(llm_txt_path) as f:
517
+ llm_txt_content = f.read()
518
+
513
519
  cookiecutter_config = {
514
520
  "project_name": "my-project",
515
521
  "agent_name": agent_name,
@@ -525,11 +531,12 @@ def process_template(
525
531
  "extra_dependencies": [extra_deps],
526
532
  "data_ingestion": include_data_ingestion,
527
533
  "datastore_type": datastore if datastore else "",
534
+ "adk_cheatsheet": adk_cheatsheet_content,
535
+ "llm_txt": llm_txt_content,
528
536
  "_copy_without_render": [
529
537
  "*.ipynb", # Don't render notebooks
530
538
  "*.json", # Don't render JSON files
531
539
  "frontend/*", # Don't render frontend directory
532
- # "tests/*", # Don't render tests directory
533
540
  "notebooks/*", # Don't render notebooks directory
534
541
  ".git/*", # Don't render git directory
535
542
  "__pycache__/*", # Don't render cache
@@ -537,15 +544,12 @@ def process_template(
537
544
  ".pytest_cache/*",
538
545
  ".venv/*",
539
546
  "*templates.py", # Don't render templates files
540
- "!*.py", # render Python files
541
- "!Makefile", # DO render Makefile
542
- "!README.md", # DO render README.md
547
+ # Don't render agent.py unless it's agentic_rag
548
+ "app/agent.py" if agent_name != "agentic_rag" else "",
543
549
  ],
544
550
  }
545
551
 
546
552
  with open(cookiecutter_template / "cookiecutter.json", "w") as f:
547
- import json
548
-
549
553
  json.dump(cookiecutter_config, f, indent=4)
550
554
 
551
555
  logging.debug(f"Template structure created at {cookiecutter_template}")
@@ -1,4 +1,5 @@
1
1
  version = 1
2
+ revision = 1
2
3
  requires-python = ">=3.9, <=3.13"
3
4
  resolution-markers = [
4
5
  "python_full_version >= '3.13'",
@@ -135,12 +136,14 @@ version = "0.1.0"
135
136
  source = { editable = "." }
136
137
  dependencies = [
137
138
  { name = "google-cloud-aiplatform" },
139
+ { name = "google-cloud-pipeline-components" },
138
140
  { name = "kfp" },
139
141
  ]
140
142
 
141
143
  [package.metadata]
142
144
  requires-dist = [
143
145
  { name = "google-cloud-aiplatform", specifier = ">=1.80.0" },
146
+ { name = "google-cloud-pipeline-components", specifier = ">=2.19.0" },
144
147
  { name = "kfp", specifier = ">=1.4.0" },
145
148
  ]
146
149
 
@@ -243,6 +246,20 @@ wheels = [
243
246
  { url = "https://files.pythonhosted.org/packages/5e/0f/2e2061e3fbcb9d535d5da3f58cc8de4947df1786fe6a1355960feb05a681/google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61", size = 29233 },
244
247
  ]
245
248
 
249
+ [[package]]
250
+ name = "google-cloud-pipeline-components"
251
+ version = "2.20.1"
252
+ source = { registry = "https://pypi.org/simple" }
253
+ dependencies = [
254
+ { name = "google-api-core" },
255
+ { name = "google-cloud-aiplatform" },
256
+ { name = "jinja2" },
257
+ { name = "kfp" },
258
+ ]
259
+ wheels = [
260
+ { url = "https://files.pythonhosted.org/packages/15/df/9840da02b887930783d23e7c966b3b1f8096f56c17ce52fa3d2682715da7/google_cloud_pipeline_components-2.20.1-py3-none-any.whl", hash = "sha256:77b3b735dc13f6868e3ed9281af3f195a1becbae0960755bb142286d784a06bd", size = 1471603 },
261
+ ]
262
+
246
263
  [[package]]
247
264
  name = "google-cloud-resource-manager"
248
265
  version = "1.14.0"
@@ -429,6 +446,18 @@ wheels = [
429
446
  { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
430
447
  ]
431
448
 
449
+ [[package]]
450
+ name = "jinja2"
451
+ version = "3.1.6"
452
+ source = { registry = "https://pypi.org/simple" }
453
+ dependencies = [
454
+ { name = "markupsafe" },
455
+ ]
456
+ sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 }
457
+ wheels = [
458
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 },
459
+ ]
460
+
432
461
  [[package]]
433
462
  name = "kfp"
434
463
  version = "2.11.0"
@@ -494,6 +523,74 @@ wheels = [
494
523
  { url = "https://files.pythonhosted.org/packages/62/a1/2027ddede72d33be2effc087580aeba07e733a7360780ae87226f1f91bd8/kubernetes-30.1.0-py2.py3-none-any.whl", hash = "sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d", size = 1706042 },
495
524
  ]
496
525
 
526
+ [[package]]
527
+ name = "markupsafe"
528
+ version = "3.0.2"
529
+ source = { registry = "https://pypi.org/simple" }
530
+ sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
531
+ wheels = [
532
+ { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 },
533
+ { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 },
534
+ { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 },
535
+ { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 },
536
+ { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 },
537
+ { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 },
538
+ { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 },
539
+ { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 },
540
+ { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 },
541
+ { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 },
542
+ { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 },
543
+ { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 },
544
+ { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 },
545
+ { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 },
546
+ { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 },
547
+ { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 },
548
+ { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 },
549
+ { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 },
550
+ { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 },
551
+ { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 },
552
+ { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 },
553
+ { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 },
554
+ { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 },
555
+ { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 },
556
+ { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 },
557
+ { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 },
558
+ { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 },
559
+ { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
560
+ { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
561
+ { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
562
+ { 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 },
563
+ { 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 },
564
+ { 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 },
565
+ { 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 },
566
+ { 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 },
567
+ { 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 },
568
+ { 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 },
569
+ { 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 },
570
+ { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
571
+ { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
572
+ { 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 },
573
+ { 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 },
574
+ { 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 },
575
+ { 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 },
576
+ { 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 },
577
+ { 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 },
578
+ { 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 },
579
+ { 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 },
580
+ { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
581
+ { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
582
+ { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 },
583
+ { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 },
584
+ { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 },
585
+ { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 },
586
+ { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 },
587
+ { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 },
588
+ { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 },
589
+ { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 },
590
+ { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 },
591
+ { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 },
592
+ ]
593
+
497
594
  [[package]]
498
595
  name = "numpy"
499
596
  version = "2.0.2"