From 89428d50d0b3fdd8189cfbe623c0cb0e3bee73c3 Mon Sep 17 00:00:00 2001 From: Simon Rosenberg Date: Wed, 14 Jan 2026 17:47:39 +0100 Subject: [PATCH] Enable SWTBench profiling and harden harness --- benchmarks/swtbench/eval_infer.py | 136 +++++++++++++++++- benchmarks/swtbench/swtbench_sitecustomize.py | 124 ++++++++++++++++ benchmarks/utils/evaluation.py | 86 ++++++++++- uv.lock | 77 +++++----- 4 files changed, 382 insertions(+), 41 deletions(-) create mode 100644 benchmarks/swtbench/swtbench_sitecustomize.py diff --git a/benchmarks/swtbench/eval_infer.py b/benchmarks/swtbench/eval_infer.py index 94cb120a..acb42df4 100644 --- a/benchmarks/swtbench/eval_infer.py +++ b/benchmarks/swtbench/eval_infer.py @@ -15,6 +15,7 @@ import shutil import subprocess import sys +import time from pathlib import Path from benchmarks.utils.laminar import LaminarService @@ -26,6 +27,64 @@ logger = get_logger(__name__) +def _write_profile_sitecustomize(swt_bench_dir: Path, profile_output: Path) -> None: + """ + Drop a sitecustomize.py into the swt-bench checkout to capture internal timings. + + This script is picked up automatically by Python when running swt-bench's + src/main.py. It records coarse phases (docker builds, run_instances, per-instance + execution) and writes them to SWTBench profile JSON. + """ + site_path = swt_bench_dir / "sitecustomize.py" + template_path = Path(__file__).parent / "swtbench_sitecustomize.py" + site_path.write_text(template_path.read_text()) + + +def _patch_swtbench_circular_import(swt_bench_dir: Path) -> None: + """ + Remove the src.main import from swt-bench/src/__init__.py to avoid the + circular import that breaks src/main.py when run as a script. + """ + init_file = swt_bench_dir / "src" / "__init__.py" + if not init_file.exists(): + logger.warning("swt-bench src/__init__.py not found; skipping patch") + return + + original = init_file.read_text() + lines = original.splitlines() + + patched: list[str] = [] + skipping_block = False + paren_balance = 0 + removed = False + + for line in lines: + if skipping_block: + paren_balance += line.count("(") - line.count(")") + if paren_balance <= 0: + skipping_block = False + continue + + if "from src.main import" in line: + removed = True + paren_balance = line.count("(") - line.count(")") + if paren_balance > 0: + skipping_block = True + continue + + patched.append(line) + + if not removed: + logger.info("No src.main re-export found in %s; no patch needed", init_file) + return + + trailing_newline = "\n" if original.endswith("\n") else "" + init_file.write_text("\n".join(patched) + trailing_newline) + logger.info( + "Removed src.main re-export from %s to avoid circular import", init_file + ) + + def _load_prediction_instance_ids(predictions_file: Path) -> list[str]: instance_ids: list[str] = [] seen = set() @@ -192,6 +251,29 @@ def run_swtbench_evaluation( """ logger.info(f"Running SWT-Bench evaluation on {predictions_file}") + timeline: list[dict[str, object]] = [] + eval_start_ns = time.perf_counter_ns() + success = False + predictions_path = Path(predictions_file).resolve() + profile_output = predictions_path.parent / ( + predictions_path.stem + ".swtbench_harness.profile.json" + ) + timeline_file = predictions_path.parent / ( + predictions_path.stem + ".swtbench_eval.timeline.json" + ) + + def record(phase: str, start_ns: int, extra: dict[str, object] | None = None): + end_ns = time.perf_counter_ns() + entry: dict[str, object] = { + "phase": phase, + "start_ns": start_ns, + "end_ns": end_ns, + "duration_ms": (end_ns - start_ns) / 1_000_000, + } + if extra: + entry.update(extra) + timeline.append(entry) + try: # Use a global cache directory for SWT-Bench source cache_dir = Path.home() / ".cache" / "openhands" / "swt-bench" @@ -199,6 +281,7 @@ def run_swtbench_evaluation( # Clone SWT-Bench repository if it doesn't exist if not swt_bench_dir.exists(): + clone_start = time.perf_counter_ns() logger.info("Setting up SWT-Bench source in global cache...") cache_dir.mkdir(parents=True, exist_ok=True) @@ -214,20 +297,31 @@ def run_swtbench_evaluation( raise subprocess.CalledProcessError(result.returncode, clone_cmd) logger.info(f"SWT-Bench source installed at {swt_bench_dir}") + record("clone_swt_bench", clone_start) + else: + record("reuse_swt_bench_cache", time.perf_counter_ns()) # Get the directory and filename of the predictions file predictions_path = Path(predictions_file).resolve() predictions_filename = predictions_path.name # Copy predictions file to swt-bench directory + copy_start = time.perf_counter_ns() swt_predictions_file = swt_bench_dir / predictions_filename shutil.copy2(predictions_file, swt_predictions_file) + record("copy_predictions", copy_start) + + # Install a profiling sitecustomize so we can capture harness timings + _write_profile_sitecustomize(swt_bench_dir, profile_output) + # Patch upstream circular import (src/__init__.py -> src.main -> run_evaluation) + _patch_swtbench_circular_import(swt_bench_dir) # Run SWT-Bench evaluation by running python directly from the swt-bench directory # but using the uv environment's python executable which has all dependencies benchmarks_dir = Path(__file__).parent.parent.parent # Get the python executable from the uv environment + python_start = time.perf_counter_ns() python_executable = subprocess.run( [ "uv", @@ -242,10 +336,16 @@ def run_swtbench_evaluation( text=True, cwd=benchmarks_dir, ).stdout.strip() + record("resolve_python_executable", python_start) # Set up environment with PYTHONPATH to include swt-bench directory env = os.environ.copy() - env["PYTHONPATH"] = str(swt_bench_dir) + env["PYTHONPATH"] = ( + f"{swt_bench_dir}:{env['PYTHONPATH']}" + if env.get("PYTHONPATH") + else str(swt_bench_dir) + ) + env["SWTBENCH_PROFILE_JSON"] = str(profile_output) cmd = [ python_executable, @@ -269,7 +369,13 @@ def run_swtbench_evaluation( print("-" * 80) # Stream output directly to console, running from swt-bench directory + harness_start = time.perf_counter_ns() result = subprocess.run(cmd, text=True, cwd=swt_bench_dir, env=env) + record( + "swtbench_harness", + harness_start, + {"returncode": result.returncode, "cmd": cmd}, + ) print("-" * 80) if result.returncode == 0: @@ -279,7 +385,12 @@ def run_swtbench_evaluation( f"SWT-Bench evaluation failed with return code {result.returncode}" ) raise subprocess.CalledProcessError(result.returncode, cmd) - + record( + "swtbench_eval_total", + eval_start_ns, + {"events_recorded": len(timeline)}, + ) + success = True except FileNotFoundError: logger.error( "SWT-Bench evaluation command not found. " @@ -289,6 +400,27 @@ def run_swtbench_evaluation( except Exception as e: logger.error(f"Error running SWT-Bench evaluation: {e}") raise + finally: + if not success: + record( + "swtbench_eval_total", + eval_start_ns, + {"events_recorded": len(timeline), "status": "error"}, + ) + timeline_payload = { + "predictions_file": str(predictions_file), + "dataset": dataset, + "workers": workers, + "started_ns": eval_start_ns, + "ended_ns": time.perf_counter_ns(), + "status": "ok" if success else "error", + "events": timeline, + } + try: + timeline_file.write_text(json.dumps(timeline_payload, indent=2)) + logger.info("Wrote timeline to %s", timeline_file) + except Exception as e: # noqa: BLE001 + logger.warning("Failed to write SWTBench timeline: %s", e) def main() -> None: diff --git a/benchmarks/swtbench/swtbench_sitecustomize.py b/benchmarks/swtbench/swtbench_sitecustomize.py new file mode 100644 index 00000000..10ccc401 --- /dev/null +++ b/benchmarks/swtbench/swtbench_sitecustomize.py @@ -0,0 +1,124 @@ +""" +Runtime-injected sitecustomize for SWT-Bench harness profiling. + +This file is copied into the swt-bench checkout as sitecustomize.py to collect +coarse-grained timing events without modifying upstream code. It is activated +only when PROFILE_SWTBENCH/SWTBENCH_PROFILE_JSON are set by the caller. +""" + +import atexit +import importlib +import json +import os +import threading +import time +from pathlib import Path +from typing import Any, Dict, Optional + + +PROFILE_PATH = os.environ.get("SWTBENCH_PROFILE_JSON", "swtbench_profile.json") +_events: list[Dict[str, Any]] = [] +_lock = threading.Lock() +_start_ns = time.perf_counter_ns() + + +def _record(name: str, extra: Optional[Dict[str, Any]] = None): + start_ns = time.perf_counter_ns() + + def _end(status: str = "ok", extra_end: Optional[Dict[str, Any]] = None): + end_ns = time.perf_counter_ns() + payload: Dict[str, Any] = { + "name": name, + "status": status, + "start_ns": start_ns, + "end_ns": end_ns, + "duration_ms": (end_ns - start_ns) / 1_000_000, + } + if extra: + payload.update(extra) + if extra_end: + payload.update(extra_end) + with _lock: + _events.append(payload) + + return _end + + +def _safe_patch(module, attr: str, wrapper): + try: + original = getattr(module, attr) + setattr(module, attr, wrapper(original)) + except Exception: + # If patching fails, skip silently to avoid impacting the harness. + return + + +# Patch swt-bench functions if available +try: + run_evaluation = importlib.import_module("run_evaluation") # type: ignore[assignment] + + def _wrap_run_instances(original): + def _inner(predictions, instances, *args, **kwargs): + done = _record( + "run_instances", + {"instance_count": len(instances) if instances is not None else None}, + ) + try: + return original(predictions, instances, *args, **kwargs) + finally: + done() + + return _inner + + def _wrap_run_eval_exec_spec(original): + def _inner(exec_spec, model_patch, *args, **kwargs): + done = _record( + "run_eval_exec_spec", + {"instance_id": getattr(exec_spec, "instance_id", None)}, + ) + try: + return original(exec_spec, model_patch, *args, **kwargs) + finally: + done() + + return _inner + + _safe_patch(run_evaluation, "run_instances", _wrap_run_instances) + _safe_patch(run_evaluation, "run_eval_exec_spec", _wrap_run_eval_exec_spec) +except Exception: + pass + +try: + docker_build = importlib.import_module("src.docker_build") # type: ignore[assignment] + + def _wrap_build_image(original): + def _inner(image_name, *args, **kwargs): + done = _record("docker_build", {"image_name": image_name}) + try: + return original(image_name, *args, **kwargs) + finally: + done() + + return _inner + + _safe_patch(docker_build, "build_image", _wrap_build_image) +except Exception: + pass + + +def _flush() -> None: + end_ns = time.perf_counter_ns() + payload = { + "started_ns": _start_ns, + "ended_ns": end_ns, + "duration_ms": (end_ns - _start_ns) / 1_000_000, + "events": _events, + } + try: + Path(PROFILE_PATH).write_text(json.dumps(payload, indent=2)) + except Exception: + # Avoid raising during interpreter shutdown + return + + +atexit.register(_flush) diff --git a/benchmarks/utils/evaluation.py b/benchmarks/utils/evaluation.py index cf4ba2cc..ce303e90 100644 --- a/benchmarks/utils/evaluation.py +++ b/benchmarks/utils/evaluation.py @@ -6,6 +6,7 @@ import json import os import sys +import time from abc import ABC, abstractmethod from concurrent.futures import ProcessPoolExecutor, as_completed from contextlib import contextmanager @@ -14,6 +15,7 @@ from typing import Callable, List, Optional, Tuple from uuid import UUID +import numpy as np from lmnr import Laminar from pydantic import BaseModel, Field from tqdm import tqdm @@ -299,6 +301,17 @@ def _run_iterative_mode( # Create attempt-specific output callback attempt_outputs: List[EvalOutput] = [] + def _make_json_safe(value: object) -> object: + if isinstance(value, np.ndarray): + return value.tolist() + if isinstance(value, np.generic): + return value.item() + if isinstance(value, dict): + return {k: _make_json_safe(v) for k, v in value.items()} + if isinstance(value, (list, tuple)): + return [_make_json_safe(v) for v in value] + return value + def attempt_on_result(instance: EvalInstance, out: EvalOutput) -> None: attempt_outputs.append(out) # Write to attempt-specific file @@ -307,8 +320,9 @@ def attempt_on_result(instance: EvalInstance, out: EvalOutput) -> None: f"output.critic_attempt_{attempt}.jsonl", ) try: - with open(attempt_file, "a") as f: - f.write(out.model_dump_json() + "\n") + payload = _make_json_safe(out.model_dump(mode="json")) + with open(attempt_file, "a", encoding="utf-8") as f: + f.write(json.dumps(payload) + "\n") except Exception as e: logger.warning( f"Failed to write to attempt file {attempt_file}: {e}" @@ -462,6 +476,13 @@ def _process_one_mp( - Ensures proper context-managed cleanup - Returns (instance, output) so the parent can stream results """ + timeline_dir = Path(self.metadata.eval_output_dir) / "timelines" + timeline_dir.mkdir(parents=True, exist_ok=True) + + def write_timeline(entry: dict[str, object]) -> None: + path = timeline_dir / f"{instance.id}.attempt{entry.get('attempt', 0)}.json" + path.write_text(json.dumps(entry, indent=2)) + # Set up instance-specific logging log_dir = os.path.join(self.metadata.eval_output_dir, "logs") reset_logger_for_multiprocessing(log_dir, instance.id) @@ -481,6 +502,12 @@ def _process_one_mp( while retry_count <= max_retries: workspace = None + attempt_index = retry_count + 1 + attempt_start_ns = time.perf_counter_ns() + attempt_start_ts = datetime.now(timezone.utc).isoformat() + attempt_status = "error" + phases: list[dict[str, int | str]] = [] + resource_factor = self.metadata.base_resource_factor # Start Laminar execution span and inject context into os.environ so workspace can pick it up # Escape the serialized context to safely pass as a cli argument @@ -507,11 +534,19 @@ def _process_one_mp( f"resource_factor={resource_factor}" ) + ws_start = time.perf_counter_ns() workspace = self.prepare_workspace( instance, resource_factor=resource_factor, forward_env=LMNR_ENV_VARS, ) + phases.append( + { + "name": "prepare_workspace", + "start_ns": int(ws_start), + "end_ns": int(time.perf_counter_ns()), + } + ) # Record runtime/pod mapping only for remote runtimes if isinstance(workspace, APIRemoteWorkspace): @@ -536,10 +571,19 @@ def _process_one_mp( runtime_run.session_id, runtime_run.resource_factor, ) + eval_start = time.perf_counter_ns() out = self.evaluate_instance(instance, workspace) + phases.append( + { + "name": "evaluate_instance", + "start_ns": int(eval_start), + "end_ns": int(time.perf_counter_ns()), + } + ) if runtime_runs: out.runtime_runs = runtime_runs logger.info("[child] done id=%s", instance.id) + attempt_status = "ok" return instance, out except Exception as e: last_error = e @@ -594,6 +638,7 @@ def _process_one_mp( return instance, error_output finally: # Ensure workspace cleanup happens regardless of success or failure + cleanup_start = time.perf_counter_ns() if workspace is not None: try: self._capture_conversation_archive(workspace, instance) @@ -615,6 +660,43 @@ def _process_one_mp( f"{str(cleanup_error)[:50]}" ) lmnr_span.end() + phases.append( + { + "name": "cleanup", + "start_ns": int(cleanup_start), + "end_ns": int(time.perf_counter_ns()), + } + ) + attempt_end_ns = time.perf_counter_ns() + write_timeline( + { + "instance_id": instance.id, + "attempt": attempt_index, + "critic_attempt": critic_attempt, + "status": attempt_status, + "error": ( + str(last_error) if attempt_status != "ok" else None + ), + "start_ts": attempt_start_ts, + "end_ts": datetime.now(timezone.utc).isoformat(), + "duration_ms": (attempt_end_ns - attempt_start_ns) + / 1_000_000, + "resource_factor": resource_factor, + "runtime_failure_count": runtime_failure_count, + "phases": [ + { + "name": p["name"], + "duration_ms": ( + (int(p["end_ns"]) - int(p["start_ns"])) + / 1_000_000 + ), + "start_ns": int(p["start_ns"]), + "end_ns": int(p["end_ns"]), + } + for p in phases + ], + } + ) # This should never be reached, but added for type safety error_output = self._create_error_output( diff --git a/uv.lock b/uv.lock index 9639461b..f8c7cb1e 100644 --- a/uv.lock +++ b/uv.lock @@ -947,11 +947,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.19.1" +version = "3.20.3" 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" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, ] [[package]] @@ -1678,11 +1678,11 @@ wheels = [ [[package]] name = "libtmux" -version = "0.46.2" +version = "0.53.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/aa/7e1dcaa097156d6f3a7d8669be4389dced997feeb81744e3ff4681d65ee8/libtmux-0.46.2.tar.gz", hash = "sha256:9a398fec5d714129c8344555d466e1a903dfc0f741ba07aabe75a8ceb25c5dda", size = 346887, upload-time = "2025-05-26T19:40:04.096Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/28/e2b252817cb181aec2f42fe2d1d7fac5ec9c4d15bfb2b8ea4bd1179e4244/libtmux-0.53.0.tar.gz", hash = "sha256:1d19af4cea0c19543954d7e7317c7025c0739b029cccbe3b843212fae238f1bd", size = 405001, upload-time = "2025-12-14T11:59:11.337Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/2f/9d207039fcfa00d3b30e4d765f062fbcc42c873c7518a8cfebb3eafd00e0/libtmux-0.46.2-py3-none-any.whl", hash = "sha256:6c32dbf22bde8e5e33b2714a4295f6e838dc640f337cd4c085a044f6828c7793", size = 60873, upload-time = "2025-05-26T19:40:02.284Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d0/2e8bc5caa639ebb9f8801ba0be7070a28d48d8ed60e2a428d40f71fb88b8/libtmux-0.53.0-py3-none-any.whl", hash = "sha256:024b7ae6a12aae55358e8feb914c8632b3ab9bd61c0987c53559643c6a58ee4f", size = 77582, upload-time = "2025-12-14T11:59:09.739Z" }, ] [[package]] @@ -2269,7 +2269,7 @@ wheels = [ [[package]] name = "openhands-agent-server" -version = "1.7.2" +version = "1.8.1" source = { editable = "vendor/software-agent-sdk/openhands-agent-server" } dependencies = [ { name = "aiosqlite" }, @@ -2405,11 +2405,12 @@ dev = [ [[package]] name = "openhands-sdk" -version = "1.7.2" +version = "1.8.1" source = { editable = "vendor/software-agent-sdk/openhands-sdk" } dependencies = [ { name = "deprecation" }, { name = "fastmcp" }, + { name = "filelock" }, { name = "httpx" }, { name = "litellm" }, { name = "lmnr" }, @@ -2430,10 +2431,11 @@ requires-dist = [ { name = "boto3", marker = "extra == 'boto3'", specifier = ">=1.35.0" }, { name = "deprecation", specifier = ">=2.1.0" }, { name = "fastmcp", specifier = ">=2.11.3" }, + { name = "filelock", specifier = ">=3.20.1" }, { name = "httpx", specifier = ">=0.27.0" }, { name = "litellm", specifier = ">=1.80.10" }, { name = "lmnr", specifier = ">=0.7.24" }, - { name = "pydantic", specifier = ">=2.11.7" }, + { name = "pydantic", specifier = ">=2.12.5" }, { name = "python-frontmatter", specifier = ">=1.1.0" }, { name = "python-json-logger", specifier = ">=3.3.0" }, { name = "tenacity", specifier = ">=9.1.2" }, @@ -2443,7 +2445,7 @@ provides-extras = ["boto3"] [[package]] name = "openhands-tools" -version = "1.7.2" +version = "1.8.1" source = { editable = "vendor/software-agent-sdk/openhands-tools" } dependencies = [ { name = "bashlex" }, @@ -2464,7 +2466,7 @@ requires-dist = [ { name = "browser-use", specifier = ">=0.8.0" }, { name = "cachetools" }, { name = "func-timeout", specifier = ">=4.3.5" }, - { name = "libtmux", specifier = ">=0.46.2" }, + { name = "libtmux", specifier = ">=0.53.0" }, { name = "openhands-sdk", editable = "vendor/software-agent-sdk/openhands-sdk" }, { name = "pydantic", specifier = ">=2.11.7" }, { name = "tom-swe", specifier = ">=1.0.3" }, @@ -2472,7 +2474,7 @@ requires-dist = [ [[package]] name = "openhands-workspace" -version = "1.7.2" +version = "1.8.1" source = { editable = "vendor/software-agent-sdk/openhands-workspace" } dependencies = [ { name = "openhands-agent-server" }, @@ -3138,21 +3140,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, - { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, - { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, - { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, @@ -3161,16 +3149,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, - { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:05.804Z" }, - { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:09.827Z" }, - { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:12.379Z" }, - { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:14.627Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:16.868Z" }, - { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, - { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, - { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },