From fa0c9b97d880f9aaa848333348382311109c7a2c Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 11:34:22 +0200 Subject: [PATCH 01/19] add Verifiers v1 CLI support --- .github/workflows/ci.yml | 32 +- .github/workflows/release-prime.yml | 2 +- packages/prime/pyproject.toml | 7 +- .../prime/src/prime_cli/commands/evals.py | 37 +- .../prime/src/prime_cli/utils/eval_push.py | 127 ++++-- .../prime/src/prime_cli/verifiers_bridge.py | 228 +++++++---- .../prime/src/prime_cli/verifiers_plugin.py | 20 +- packages/prime/tests/test_env_push_path.py | 2 +- packages/prime/tests/test_eval_billing.py | 361 ++++++++++-------- packages/prime/tests/test_eval_help.py | 21 + packages/prime/tests/test_eval_push.py | 58 +++ packages/prime/tests/test_hosted_eval.py | 74 +++- 12 files changed, 694 insertions(+), 275 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5308ad1f0..82918c126 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,20 +120,20 @@ jobs: - name: Install dependencies working-directory: packages/prime-sandboxes - run: uv sync --all-extras + run: uv pip install --system --no-config --exclude-newer "7 days" --editable ".[dev]" - name: Run tests working-directory: packages/prime-sandboxes env: PRIME_API_KEY: ${{ secrets.PRIME_API_KEY }} PRIME_TEAM_ID: ${{ secrets.PRIME_TEAM_ID }} - run: uv run pytest tests/ -v -n auto + run: python -m pytest tests/ -v -n auto test-prime: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.12", "3.13", "3.14"] + python-version: ["3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 @@ -149,14 +149,23 @@ jobs: - name: Install dependencies working-directory: packages/prime - run: uv sync --all-extras + run: | + uv sync --all-extras --frozen + uv pip install --no-config --no-sources \ + --exclude-newer "7 days" \ + --exclude-newer-package "verifiers=0 days" \ + --exclude-newer-package "prime-pydantic-config=0 days" \ + --exclude-newer-package "renderers=0 days" \ + "verifiers==0.1.15.dev371" \ + "prime-pydantic-config>=0.3.0.dev86" \ + "renderers>=0.1.8.dev40" - name: Run tests with pytest working-directory: packages/prime env: PRIME_API_KEY: ${{ secrets.PRIME_API_KEY }} PRIME_TEAM_ID: ${{ secrets.PRIME_TEAM_ID }} - run: uv run pytest tests/ -v + run: uv run --no-sync pytest tests/ -v type-check: runs-on: ubuntu-latest @@ -175,8 +184,17 @@ jobs: - name: Install dependencies working-directory: packages/prime - run: uv sync --all-extras + run: | + uv sync --all-extras --frozen + uv pip install --no-config --no-sources \ + --exclude-newer "7 days" \ + --exclude-newer-package "verifiers=0 days" \ + --exclude-newer-package "prime-pydantic-config=0 days" \ + --exclude-newer-package "renderers=0 days" \ + "verifiers==0.1.15.dev371" \ + "prime-pydantic-config>=0.3.0.dev86" \ + "renderers>=0.1.8.dev40" - name: Run ty type checker working-directory: packages/prime - run: uv run ty check src/ + run: uv run --no-sync ty check src/ diff --git a/.github/workflows/release-prime.yml b/.github/workflows/release-prime.yml index 9b31f4e95..e6d187dda 100644 --- a/.github/workflows/release-prime.yml +++ b/.github/workflows/release-prime.yml @@ -187,7 +187,7 @@ jobs: packages: write strategy: matrix: - python-version: ['3.10', '3.11', '3.12'] + python-version: ['3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v3 with: diff --git a/packages/prime/pyproject.toml b/packages/prime/pyproject.toml index 21bd9401e..31e6e56d6 100644 --- a/packages/prime/pyproject.toml +++ b/packages/prime/pyproject.toml @@ -4,7 +4,7 @@ name = "prime" dynamic = ["version"] description = "Prime Intellect CLI + SDK" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.11,<3.14" license = "MIT" authors = [ { name = "Prime Intellect", email = "contact@primeintellect.ai" } @@ -20,7 +20,7 @@ dependencies = [ "textual>=6.1.0", "textual-plot>=0.10.1", "cryptography>=41.0.0", - "verifiers>=0.1.14", + "verifiers==0.1.15.dev371", "build>=1.0.0", "gitignore-parser>=0.1.13", "pyyaml>=6.0.0", @@ -35,11 +35,9 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules" ] @@ -64,7 +62,6 @@ dev = [ prime-sandboxes = { workspace = true } prime-evals = { workspace = true } prime-tunnel = { workspace = true } -verifiers = { git = "https://github.com/PrimeIntellect-ai/verifiers.git", tag = "v0.1.14" } [build-system] requires = ["hatchling"] diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 3c1977a3f..441548f5f 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -25,7 +25,7 @@ ) from ..utils.display import get_eval_viewer_url from ..utils.env_metadata import find_environment_metadata -from ..utils.eval_push import load_results_jsonl +from ..utils.eval_push import convert_eval_results, load_results_jsonl from ..utils.hosted_eval import ( EvalStatus, HostedEvalConfig, @@ -84,7 +84,7 @@ HOSTED_LOGS_RETRY_WAIT_SECONDS = 10 HOSTED_LOGS_STATUS_UPDATE_EVERY_POLLS = 6 EVAL_TABLE_MAX_TEXT_WIDTH = 30 -EVAL_RUN_EXAMPLE_COMMAND = "prime eval run gsm8k -n 10" +EVAL_RUN_EXAMPLE_COMMAND = "prime eval run harbor_v1 -n 1" EVAL_HOSTED_LABEL = "HOSTED" EVAL_LOCAL_LABEL = "LOCAL" # Legacy verifiers config fields/flags are accepted through the parser only so @@ -924,11 +924,7 @@ def _load_eval_directory(directory: Path) -> dict: f"Missing required 'env_id' or 'model' field in {directory / 'metadata.json'}" ) - results = load_results_jsonl(directory / "results.jsonl") - - for sample in results: - if "id" in sample and "example_id" not in sample: - sample["example_id"] = sample["id"] + results = convert_eval_results(load_results_jsonl(directory / "results.jsonl")) avg_pattern = re.compile(r"^avg_(.+)$") metrics = {} @@ -1474,6 +1470,22 @@ def run_eval_cmd( ) -> None: """Run an evaluation with local-first environment resolution.""" passthrough_args = list(ctx.args) + if environment == "@": + if not passthrough_args: + console.print("[red]Error:[/red] @ must be followed by a config path.") + raise typer.Exit(2) + environment = passthrough_args.pop(0) + elif environment == "--resume": + if not passthrough_args: + console.print("[red]Error:[/red] --resume must be followed by an output directory.") + raise typer.Exit(2) + resume_dir = passthrough_args.pop(0) + environment = resume_dir + passthrough_args = ["--resume", resume_dir, *passthrough_args] + elif environment and environment.startswith("--resume="): + resume_dir = environment.split("=", 1)[1] + environment = resume_dir + passthrough_args = [f"--resume={resume_dir}", *passthrough_args] if is_help_request(environment or "", passthrough_args): print_eval_run_help() @@ -1494,10 +1506,17 @@ def run_eval_cmd( ctx.get_parameter_source("poll_interval") == ParameterSource.COMMANDLINE ) local_passthrough_args = list(passthrough_args) - if sampling_args is not None: - local_passthrough_args.extend(["--sampling-args", sampling_args]) if not hosted: + legacy_eval = "--save-results" in local_passthrough_args + if sampling_args is not None and legacy_eval: + local_passthrough_args.extend(["--sampling-args", sampling_args]) + elif sampling_args is not None: + console.print( + "[red]Error:[/red] local v1 evals use --sampling.* options " + "(for example, --sampling.temperature 0.7)" + ) + raise typer.Exit(2) hosted_only_args = { "--follow": follow, "--poll-interval": poll_interval_was_provided, diff --git a/packages/prime/src/prime_cli/utils/eval_push.py b/packages/prime/src/prime_cli/utils/eval_push.py index 5af038ccd..2e8ab7e82 100644 --- a/packages/prime/src/prime_cli/utils/eval_push.py +++ b/packages/prime/src/prime_cli/utils/eval_push.py @@ -51,12 +51,98 @@ def load_results_jsonl(path: Path) -> list[dict]: return results +def convert_eval_results(samples: list[dict]) -> list[dict]: + """Convert v1 traces to the sample schema while preserving legacy results.""" + trace_type = None + trace_fields = {} + rollout_counts: dict[int, int] = {} + converted = [] + + for sample in samples: + if not ( + isinstance(sample.get("nodes"), list) + and isinstance(sample.get("task"), dict) + and isinstance(sample.get("rewards"), dict) + ): + legacy_sample = dict(sample) + if "id" in legacy_sample and "example_id" not in legacy_sample: + legacy_sample["example_id"] = legacy_sample["id"] + converted.append(legacy_sample) + continue + + if trace_type is None: + from verifiers.v1.task import WireTask + from verifiers.v1.trace import Trace + + trace_type = Trace[WireTask] + trace_fields = trace_type.model_fields + trace = trace_type.model_validate( + {key: value for key, value in sample.items() if key in trace_fields} + ) + task = trace.task.model_dump(mode="json", exclude_none=True) + branches = trace.branches + main_messages = ( + [ + message.model_dump(mode="json", exclude_none=True) + for message in branches[-1].messages + ] + if branches + else [] + ) + trajectory = [ + { + "messages": [ + message.model_dump(mode="json", exclude_none=True) + for message in branch.messages + ], + "reward": trace.reward, + "num_input_tokens": branch.prompt_len, + "num_output_tokens": branch.completion_len, + } + for branch in branches + ] + example_id = trace.task.idx + rollout_counts[example_id] = rollout_counts.get(example_id, 0) + 1 + info = dict(trace.info) + info.update({key: value for key, value in sample.items() if key not in trace_fields}) + + converted.append( + { + "sample_id": trace.id, + "example_id": example_id, + "rollout_number": rollout_counts[example_id], + "task": task, + "prompt": [], + "completion": main_messages, + "answer": task.get("answer"), + "reward": trace.reward, + "timing": trace.timing.model_dump(mode="json", exclude_none=True), + "is_completed": trace.is_completed, + "is_truncated": trace.is_truncated, + "metrics": trace.metrics, + "error": ( + trace.error.model_dump(mode="json", exclude_none=True) if trace.error else None + ), + "stop_condition": trace.stop_condition, + "trajectory": trajectory, + "token_usage": ( + trace.usage.model_dump(mode="json", exclude_none=True) if trace.usage else None + ), + "num_steps": trace.num_turns, + "info": info or None, + } + ) + + return converted + + def push_eval_results_to_hub( env_name: str, model: str, job_id: str, env_path: Optional[Path] = None, upstream_slug: Optional[str] = None, + output_dir: Optional[Path] = None, ) -> None: """ Push evaluation results to Prime Evals Hub after `prime eval run` completes. @@ -78,23 +164,21 @@ def push_eval_results_to_hub( """ # Step 1: Find the output directory module_name = env_name.replace("-", "_") - model_name = model.replace("/", "--") - env_model_str = f"{env_name}--{model_name}" - - local_env_dir = Path("./environments") / module_name - if local_env_dir.exists(): - base_evals_dir = local_env_dir / "outputs" / "evals" / env_model_str - else: - base_evals_dir = Path("./outputs") / "evals" / env_model_str - - if not base_evals_dir.exists(): - raise FileNotFoundError(f"Evaluation output directory not found: {base_evals_dir}") - - subdirs = [d for d in base_evals_dir.iterdir() if d.is_dir()] - if not subdirs: - raise FileNotFoundError(f"No evaluation results found in {base_evals_dir}") - - output_dir = max(subdirs, key=lambda d: d.stat().st_mtime) + if output_dir is None: + model_name = model.replace("/", "--") + env_model_str = f"{env_name}--{model_name}" + local_env_dir = Path("./environments") / module_name + base_evals_dir = ( + local_env_dir / "outputs" / "evals" / env_model_str + if local_env_dir.exists() + else Path("./outputs") / "evals" / env_model_str + ) + if not base_evals_dir.exists(): + raise FileNotFoundError(f"Evaluation output directory not found: {base_evals_dir}") + subdirs = [d for d in base_evals_dir.iterdir() if d.is_dir()] + if not subdirs: + raise FileNotFoundError(f"No evaluation results found in {base_evals_dir}") + output_dir = max(subdirs, key=lambda d: d.stat().st_mtime) metadata_path = output_dir / "metadata.json" results_path = output_dir / "results.jsonl" @@ -179,14 +263,7 @@ def push_eval_results_to_hub( eval_metadata = {"framework": "verifiers", "job_id": job_id, **metadata} - converted_results = [ - { - "example_id": sample.get("id", 0), - "reward": sample.get("reward", 0.0), - **{k: v for k, v in sample.items() if k not in {"id", "reward"}}, - } - for sample in results_samples - ] + converted_results = convert_eval_results(results_samples) eval_name = f"{env_name}--{model}--{datetime.now().strftime('%Y%m%d_%H%M%S')}" diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index fe01b9aa4..155821e3f 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -2,6 +2,7 @@ from __future__ import annotations +import json import os import re import subprocess @@ -21,7 +22,7 @@ from .api.inference import InferenceAPIError, InferenceClient, InferencePaymentRequiredError from .client import APIClient, APIError from .utils.env_metadata import find_environment_metadata, get_environment_metadata -from .utils.eval_push import push_eval_results_to_hub +from .utils.eval_push import convert_eval_results, load_results_jsonl, push_eval_results_to_hub from .utils.plain import get_console from .verifiers_plugin import PrimeVerifiersPlugin, load_verifiers_prime_plugin @@ -32,17 +33,25 @@ DEFAULT_ENDPOINTS_PATH = "./configs/endpoints.toml" PRIME_SLUG = "primeintellect" INTERNAL_ENV_DISPLAY_HEADER = "X-Prime-Eval-Env-Display" +LEGACY_EVAL_MODULE = "verifiers.cli.commands.eval" EVAL_PREFLIGHT_TIMEOUT = httpx.Timeout(connect=10.0, read=300.0, write=60.0, pool=60.0) MODULE_TO_PRIME_COMMAND = { "verifiers.cli.commands.eval": "prime eval run", + "verifiers.v1.cli.eval.main": "prime eval run", "verifiers.cli.commands.gepa": "prime gepa run", "verifiers.cli.commands.init": "prime env init", + "verifiers.v1.cli.init": "prime env init", "verifiers.cli.commands.install": "prime env install", "verifiers.cli.commands.build": "prime env build", "verifiers.cli.commands.setup": "prime lab setup", "verifiers.cli.tui": "prime eval view", } +MODULE_TO_CONSOLE_SCRIPT = { + "verifiers.v1.cli.eval.main": "eval", + "verifiers.v1.cli.init": "init", +} + @dataclass(frozen=True) class ResolvedEnvironment: @@ -73,6 +82,7 @@ def is_help_request(primary_arg: str, passthrough_args: list[str]) -> bool: def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> str: lines = help_text.splitlines() + console_script = MODULE_TO_CONSOLE_SCRIPT.get(module_name) for idx, line in enumerate(lines): if line.lower().startswith("usage:"): suffix = line.split(":", 1)[1].strip() @@ -80,8 +90,11 @@ def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> rf"^python(?:\d+(?:\.\d+)?)?\s+-m\s+{re.escape(module_name)}(?:\s+|$)" ) module_prefix = re.compile(rf"^{re.escape(module_name)}(?:\s+|$)") + console_prefix = f"uv run {console_script}" if console_script else None match = python_module_prefix.match(suffix) or module_prefix.match(suffix) - if match is not None: + if console_prefix and suffix.startswith(console_prefix): + suffix = suffix[len(console_prefix) :].lstrip() + elif match is not None: suffix = suffix[match.end() :].lstrip() else: parts = suffix.split(maxsplit=1) @@ -98,6 +111,15 @@ def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> sanitized = sanitized.replace(f"python -m {module_alias}", command_alias) sanitized = sanitized.replace(module_alias, command_alias) + if console_script: + sanitized = sanitized.replace(f"uv run {console_script}", prime_command) + module_script = module_name.rsplit(".", 1)[-1] + ".py" + sanitized = re.sub( + rf"(?im)^usage: (?:{re.escape(console_script)}|{re.escape(module_script)})\b", + f"Usage: {prime_command}", + sanitized, + ) + sanitized = re.sub(r"\bvf-[a-z0-9-]+\b", prime_command, sanitized) if prime_command in {"prime eval run", "prime gepa run"}: sanitized = re.sub(r"\benv_id_or_config\b", "environment", sanitized) @@ -748,46 +770,6 @@ def _prepare_single_environment( return resolved -def _collect_eval_config_envs(config_path: Path, fallback_env_dir: str) -> list[tuple[str, str]]: - try: - raw = toml.load(config_path) - except Exception as exc: - console.print( - f"[yellow]Warning:[/yellow] Could not parse eval config {config_path}: {exc}. " - "Skipping pre-install." - ) - return [] - - if not isinstance(raw, dict): - return [] - - eval_entries = raw.get("eval") - if not isinstance(eval_entries, list): - return [] - - global_env_dir = raw.get("env_dir_path") - if not isinstance(global_env_dir, str): - global_env_dir = fallback_env_dir - - resolved: list[tuple[str, str]] = [] - seen: set[tuple[str, str]] = set() - for entry in eval_entries: - if not isinstance(entry, dict): - continue - env_id = entry.get("env_id") or entry.get("id") - if not isinstance(env_id, str) or not env_id: - continue - env_dir_path = entry.get("env_dir_path") - if not isinstance(env_dir_path, str): - env_dir_path = global_env_dir - key = (env_id, env_dir_path) - if key in seen: - continue - seen.add(key) - resolved.append(key) - return resolved - - def _env_name_from_reference(env_reference: str) -> str: base_ref, _version = _split_version(env_reference) return base_ref.rsplit("/", 1)[-1] @@ -958,56 +940,173 @@ def run_eval_passthrough( ) raise typer.Exit(1) - args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) - configured_base_url = (config.inference_url or "").strip().rstrip("/") - _validate_model(model, base_url, configured_base_url) - _preflight_inference_billing(model, base_url, configured_base_url) + if any(arg == "--resume" or arg.startswith("--resume=") for arg in passthrough_args): + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + command = plugin.build_module_command(plugin.eval_module, passthrough_args) + _run_command(command, env=env) + return - env_dir_path = _env_dir_path_arg(args) - run_target = environment + # Hosted-eval sandboxes still emit the v0 CLI surface; v1 always saves results. + if "--save-results" in passthrough_args: + args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) + configured_base_url = (config.inference_url or "").strip().rstrip("/") + _validate_model(model, base_url, configured_base_url) + _preflight_inference_billing(model, base_url, configured_base_url) + + env_dir_path = _env_dir_path_arg(args) + resolved_env = _prepare_single_environment(plugin, environment, env_dir_path) + if resolved_env.env_display_id: + args.extend( + ["--header", f"{INTERNAL_ENV_DISPLAY_HEADER}: {resolved_env.env_display_id}"] + ) + + job_id = _build_job_id(resolved_env.env_name, model) + args.extend(["--header", f"X-PI-Job-Id: {job_id}"]) + if config.team_id: + args.extend(["--header", f"X-Prime-Team-ID: {config.team_id}"]) + + console.print(f"[dim]Eval job_id: {job_id}[/dim]") + command = plugin.build_module_command(LEGACY_EVAL_MODULE, [resolved_env.env_name, *args]) + _run_command(command, env=env) + + if skip_upload: + _print_environment_source_footer(resolved_env) + console.print("[dim]Skipped uploading evaluation results[/dim]") + return + + push_eval_results_to_hub( + env_name=resolved_env.env_name, + model=model, + job_id=job_id, + env_path=Path(env_path) if env_path else None, + upstream_slug=resolved_env.upstream_slug, + ) + _print_environment_source_footer(resolved_env) + return + + target = environment.removeprefix("@") + is_config = _is_config_target(target) + args = list(passthrough_args) + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + + config_data = toml.load(target) if is_config else {} + config_model = config_data.get("model") if isinstance(config_data, dict) else None + model = _parse_value_option(args, "--model", "-m") or config_model or DEFAULT_MODEL + if _parse_value_option(args, "--model", "-m") is None and not config_model: + args.extend(["--model", model]) + + configured_base_url = (config.inference_url or "").strip().rstrip("/") + config_client = config_data.get("client") if isinstance(config_data, dict) else None + config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None + base_url = ( + _parse_value_option(args, "--client.base-url", None) + or config_base_url + or configured_base_url + ) + if not base_url: + console.print( + "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." + ) + raise typer.Exit(1) + dry_run_arg = _parse_value_option(args, "--dry-run", None) + dry_run = config_data.get("dry_run") is True + if dry_run_arg is not None: + dry_run = dry_run_arg.lower() == "true" + if not dry_run: + _validate_model(model, base_url, configured_base_url) + _preflight_inference_billing(model, base_url, configured_base_url) + + env_dir_path = DEFAULT_ENV_DIR_PATH + run_target = target upstream_slug: Optional[str] = None env_name_for_upload: Optional[str] = None resolved_env: Optional[ResolvedEnvironment] = None config_envs: list[tuple[str, str]] = [] - if _is_config_target(environment): - config_envs = _collect_eval_config_envs(Path(environment), env_dir_path) + if is_config: + taskset = config_data.get("taskset", {}) + if isinstance(taskset, dict) and isinstance(taskset.get("id"), str): + config_envs = [(taskset["id"], env_dir_path)] for env_ref, ref_env_dir in config_envs: _prepare_single_environment(plugin, env_ref, ref_env_dir) + run_target = f"@{target}" else: - resolved_env = _prepare_single_environment(plugin, environment, env_dir_path) + resolved_env = _prepare_single_environment(plugin, target, env_dir_path) run_target = resolved_env.env_name upstream_slug = resolved_env.upstream_slug env_name_for_upload = resolved_env.env_name - if resolved_env.env_display_id: - args.extend( - ["--header", f"{INTERNAL_ENV_DISPLAY_HEADER}: {resolved_env.env_display_id}"] - ) - - if not skip_upload and not _has_flag(args, "--save-results", "-s"): - args.append("-s") job_target = env_name_for_upload if job_target is None and config_envs: job_target = _env_name_from_reference(config_envs[0][0]) if job_target is None: - job_target = Path(environment).stem + job_target = Path(target).stem job_id = _build_job_id(job_target, model) - args.extend(["--header", f"X-PI-Job-Id: {job_id}"]) - - if config.team_id: - args.extend(["--header", f"X-Prime-Team-ID: {config.team_id}"]) + output_dir_arg = _parse_value_option(args, "--output-dir", "-o") + config_output_dir = config_data.get("output_dir") if isinstance(config_data, dict) else None + configured_output_dir = output_dir_arg or config_output_dir + output_dir = ( + Path(configured_output_dir) + if configured_output_dir + else Path("outputs", "evals", f"{job_target}--{model.replace('/', '--')}", job_id) + ) + if configured_output_dir is None: + args.extend(["--output-dir", str(output_dir)]) + + headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} + if not isinstance(headers, dict): + console.print("[red]Error:[/red] client.headers must be a table") + raise typer.Exit(2) + cli_headers = _parse_value_option(args, "--client.headers", None) + if cli_headers: + try: + parsed_headers = json.loads(cli_headers) + except json.JSONDecodeError as exc: + console.print("[red]Error:[/red] --client.headers must be valid JSON") + raise typer.Exit(2) from exc + if not isinstance(parsed_headers, dict): + console.print("[red]Error:[/red] --client.headers must be a JSON object") + raise typer.Exit(2) + headers = {**headers, **parsed_headers} + headers["X-PI-Job-Id"] = job_id + if resolved_env is not None and resolved_env.env_display_id: + headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id + args.extend(["--client.headers", json.dumps(headers)]) console.print(f"[dim]Eval job_id: {job_id}[/dim]") command = plugin.build_module_command(plugin.eval_module, [run_target, *args]) _run_command(command, env=env) + results_path = output_dir / "results.jsonl" + if not results_path.exists(): + console.print("[dim]No rollout results produced.[/dim]") + return + results = convert_eval_results(load_results_jsonl(results_path)) + task_ids = {row["example_id"] for row in results if "example_id" in row} + rewards = [row["reward"] for row in results if isinstance(row.get("reward"), (int, float))] + metadata = { + "env": job_target, + "model": model, + "num_examples": len(task_ids), + "rollouts_per_example": len(results) // len(task_ids) if task_ids else 0, + "avg_reward": sum(rewards) / len(rewards) if rewards else 0.0, + } + (output_dir / "metadata.json").write_text( + json.dumps(metadata, indent=2) + "\n", encoding="utf-8" + ) + if skip_upload: _print_environment_source_footer(resolved_env) console.print("[dim]Skipped uploading evaluation results[/dim]") return - if _is_config_target(environment): + if is_config: console.print( "[yellow]Evaluation completed. Automatic upload is skipped for " "config-driven runs.[/yellow]" @@ -1054,6 +1153,7 @@ def run_eval_passthrough( job_id=job_id, env_path=Path(env_path) if env_path else None, upstream_slug=upstream_slug, + output_dir=output_dir, ) except Exception as exc: console.print(f"[red]Failed to push results to hub:[/red] {exc}") diff --git a/packages/prime/src/prime_cli/verifiers_plugin.py b/packages/prime/src/prime_cli/verifiers_plugin.py index 378d3163e..705bdf277 100644 --- a/packages/prime/src/prime_cli/verifiers_plugin.py +++ b/packages/prime/src/prime_cli/verifiers_plugin.py @@ -16,6 +16,12 @@ from .utils.plain import get_console EXPECTED_PLUGIN_API_VERSION = 1 +V1_EVAL_MODULE = "verifiers.v1.cli.eval.main" +V1_INIT_MODULE = "verifiers.v1.cli.init" +V1_ENTRYPOINTS = { + V1_EVAL_MODULE: f"import sys; sys.argv[0] = 'eval'; from {V1_EVAL_MODULE} import main; main()", + V1_INIT_MODULE: f"import sys; sys.argv[0] = 'init'; from {V1_INIT_MODULE} import main; main()", +} def _venv_python(venv_root: Path) -> Path: @@ -47,7 +53,7 @@ def resolve_workspace_python(cwd: Path | None = None) -> str: """Prefer workspace Python only when it can run verifiers command modules.""" workspace = (cwd or Path.cwd()).resolve() workspace_str = str(workspace) - module = "verifiers.cli.commands.eval" + module = V1_EVAL_MODULE def _usable(candidate: Path) -> bool: return candidate.exists() and _python_can_import_module( @@ -80,10 +86,10 @@ class PrimeVerifiersPlugin: """Local fallback contract used when verifiers plugin loading fails.""" api_version: int = EXPECTED_PLUGIN_API_VERSION - eval_module: str = "verifiers.cli.commands.eval" + eval_module: str = V1_EVAL_MODULE gepa_module: str = "verifiers.cli.commands.gepa" install_module: str = "verifiers.cli.commands.install" - init_module: str = "verifiers.cli.commands.init" + init_module: str = V1_INIT_MODULE setup_module: str = "verifiers.cli.commands.setup" build_module: str = "verifiers.cli.commands.build" tui_module: str = "verifiers.cli.tui" @@ -91,7 +97,9 @@ class PrimeVerifiersPlugin: def build_module_command( self, module_name: str, args: Sequence[str] | None = None ) -> list[str]: - command = [resolve_workspace_python(), "-m", module_name] + python = resolve_workspace_python() + entrypoint = V1_ENTRYPOINTS.get(module_name) + command = [python, "-c", entrypoint] if entrypoint else [python, "-m", module_name] if args: command.extend(args) return command @@ -136,10 +144,10 @@ def load_verifiers_prime_plugin(console: Console | None = None) -> PrimeVerifier return PrimeVerifiersPlugin( api_version=int(api_version or EXPECTED_PLUGIN_API_VERSION), - eval_module=getattr(plugin, "eval_module", "verifiers.cli.commands.eval"), + eval_module=V1_EVAL_MODULE, gepa_module=getattr(plugin, "gepa_module", "verifiers.cli.commands.gepa"), install_module=getattr(plugin, "install_module", "verifiers.cli.commands.install"), - init_module=getattr(plugin, "init_module", "verifiers.cli.commands.init"), + init_module=V1_INIT_MODULE, setup_module=getattr(plugin, "setup_module", "verifiers.cli.commands.setup"), build_module=getattr(plugin, "build_module", "verifiers.cli.commands.build"), tui_module=getattr(plugin, "tui_module", "verifiers.cli.tui"), diff --git a/packages/prime/tests/test_env_push_path.py b/packages/prime/tests/test_env_push_path.py index 55db8fb9e..f16823f74 100644 --- a/packages/prime/tests/test_env_push_path.py +++ b/packages/prime/tests/test_env_push_path.py @@ -123,7 +123,7 @@ def test_env_init_runs_lab_hygiene_preflight_inside_lab_workspace(tmp_path, monk ) class DummyPlugin: - init_module = "verifiers.cli.commands.init" + init_module = "verifiers.v1.cli.init" def build_module_command(self, module, args): return ["verifiers-init", module, *args] diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 0bc743666..88317c66e 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -1,3 +1,6 @@ +import json +from pathlib import Path + import httpx import pytest import typer @@ -21,7 +24,7 @@ class DummyConfig: class DummyPlugin: - eval_module = "verifiers.cli.commands.eval" + eval_module = "verifiers.v1.cli.eval.main" gepa_module = "verifiers.cli.commands.gepa" def build_module_command(self, module: str, args: list[str]) -> list[str]: @@ -146,24 +149,8 @@ def chat_completion(self, payload, stream=False): assert all(timeout.read == 300.0 for timeout in seen_timeouts) -def test_eval_run_model_alias_uses_local_endpoint_registry(monkeypatch, tmp_path): +def test_eval_run_uses_v1_client_config(monkeypatch, tmp_path): monkeypatch.chdir(tmp_path) - config_dir = tmp_path / "configs" - config_dir.mkdir() - (config_dir / "endpoints.toml").write_text( - "\n".join( - [ - "[[endpoint]]", - 'endpoint_id = "gpt-4.1-mini"', - 'model = "gpt-4.1-mini"', - 'url = "https://api.openai.com/v1"', - 'key = "OPENAI_API_KEY"', - 'type = "openai_chat_completions"', - "", - ] - ), - encoding="utf-8", - ) monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) @@ -190,146 +177,125 @@ def __init__(self, timeout=None): run_eval_passthrough( environment="goblin-questions", - passthrough_args=["-m", "gpt-4.1-mini", "-n", "1"], + passthrough_args=[ + "-m", + "gpt-4.1-mini", + "--client.base-url", + "https://api.openai.com/v1", + "--client.headers", + '{"X-Test": "yes"}', + "-n", + "1", + ], skip_upload=True, env_path=None, ) command = captured["command"] - assert command[:3] == ["verifiers.cli.commands.eval", "goblin-questions", "-m"] + assert command[:3] == ["verifiers.v1.cli.eval.main", "goblin-questions", "-m"] assert "gpt-4.1-mini" in command - assert "-b" not in command assert "--api-base-url" not in command - assert "-k" not in command assert "--api-key-var" not in command + header_idx = len(command) - 1 - command[::-1].index("--client.headers") + headers = json.loads(command[header_idx + 1]) + assert headers["X-Test"] == "yes" + assert headers["X-PI-Job-Id"].startswith("goblin_questions_gpt_4.1_mini_") assert captured["env"]["PRIME_API_KEY"] == "test-api-key" -def test_eval_run_missing_endpoint_registry_falls_back_to_configured_inference( - monkeypatch, - tmp_path, -): - monkeypatch.chdir(tmp_path) +def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - - def fail_load_endpoints(_path): - raise AssertionError("missing endpoint registry should not be loaded") - - monkeypatch.setattr("verifiers.utils.eval_utils.load_endpoints", fail_load_endpoints) - - seen_payloads = [] - - class DummyInferenceClient: - def __init__(self, timeout=None): - pass - - def retrieve_model(self, model): - return {"id": model} - - def chat_completion(self, payload, stream=False): - seen_payloads.append(payload) - return {"id": "cmpl-123", "choices": []} - - monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) + monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", - lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), + "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None ) - - with pytest.raises(typer.Exit) as exc_info: - run_eval_passthrough( - environment="single_turn_math", - passthrough_args=["-m", "openai/gpt-4.1-mini"], - skip_upload=False, - env_path=None, - ) - - assert cast(typer.Exit, exc_info.value).exit_code == 0 - assert seen_payloads == [ - { - "model": "openai/gpt-4.1-mini", - "messages": [{"role": "user", "content": "Reply with OK."}], - } - ] - - -def test_eval_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge._prepare_single_environment", + lambda *_args: ResolvedEnvironment( + original="legacy-env", env_name="legacy-env", install_mode="local" + ), ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) captured = {} monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, environment, env_dir_path: captured.update( - {"environment": environment, "env_dir_path": env_dir_path} - ) - or ResolvedEnvironment( - original=environment, - env_name=environment, - install_mode="local", - ), + "prime_cli.verifiers_bridge._run_command", + lambda command, env=None: captured.update(command=command, env=env), ) - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda command, env=None: None) run_eval_passthrough( - environment="single_turn_math", - passthrough_args=["-p", "openai", "-m", "gpt-4.1-mini"], + environment="legacy-env", + passthrough_args=[ + "--save-results", + "--debug", + "--num-examples", + "1", + "--rollouts-per-example", + "2", + ], skip_upload=True, env_path=None, ) - assert captured == { - "environment": "single_turn_math", - "env_dir_path": "./environments", - } + assert captured["command"][0] == "verifiers.cli.commands.eval" + assert "--save-results" in captured["command"] + assert "--debug" in captured["command"] + assert "--client.headers" not in captured["command"] -def test_eval_run_empty_passthrough_arg_does_not_override_env_dir_path(monkeypatch, tmp_path): +def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._validate_model", + lambda *_args: (_ for _ in ()).throw(AssertionError("resume must skip model validation")), + ) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._preflight_inference_billing", + lambda *_args: (_ for _ in ()).throw(AssertionError("resume must skip billing preflight")), + ) captured = {} - envs_path = str(tmp_path / "envs") monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, environment, env_dir_path: captured.update( - {"environment": environment, "env_dir_path": env_dir_path} - ) - or ResolvedEnvironment( - original=environment, - env_name=environment, - install_mode="local", - ), + "prime_cli.verifiers_bridge._run_command", + lambda command, env=None: captured.update(command=command, env=env), ) - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda command, env=None: None) + output_dir = tmp_path / "previous-run" run_eval_passthrough( - environment="single_turn_math", - passthrough_args=["-p", "openai", "", envs_path, "-m", "gpt-4.1-mini"], + environment=str(output_dir), + passthrough_args=["--resume", str(output_dir)], skip_upload=True, env_path=None, ) - assert captured == { - "environment": "single_turn_math", - "env_dir_path": "./environments", - } + assert captured["command"] == [ + "verifiers.v1.cli.eval.main", + "--resume", + str(output_dir), + ] + assert captured["env"]["PRIME_API_KEY"] == "test-api-key" -def test_eval_run_uses_long_env_dir_path_without_treating_it_as_provider( +def test_eval_run_missing_endpoint_registry_falls_back_to_configured_inference( monkeypatch, tmp_path, ): + monkeypatch.chdir(tmp_path) monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + def fail_load_endpoints(_path): + raise AssertionError("missing endpoint registry should not be loaded") + + monkeypatch.setattr("verifiers.utils.eval_utils.load_endpoints", fail_load_endpoints) + + seen_payloads = [] + class DummyInferenceClient: def __init__(self, timeout=None): pass @@ -338,35 +304,30 @@ def retrieve_model(self, model): return {"id": model} def chat_completion(self, payload, stream=False): + seen_payloads.append(payload) return {"id": "cmpl-123", "choices": []} - captured = {} - envs_path = str(tmp_path / "envs") monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, environment, env_dir_path: captured.update( - {"environment": environment, "env_dir_path": env_dir_path} - ) - or ResolvedEnvironment( - original=environment, - env_name=environment, - install_mode="local", - ), + lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), ) - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda command, env=None: None) - run_eval_passthrough( - environment="single_turn_math", - passthrough_args=["--env-dir-path", envs_path, "-m", "openai/gpt-4.1-mini"], - skip_upload=True, - env_path=None, - ) + with pytest.raises(typer.Exit) as exc_info: + run_eval_passthrough( + environment="single_turn_math", + passthrough_args=["-m", "openai/gpt-4.1-mini"], + skip_upload=False, + env_path=None, + ) - assert captured == { - "environment": "single_turn_math", - "env_dir_path": envs_path, - } + assert cast(typer.Exit, exc_info.value).exit_code == 0 + assert seen_payloads == [ + { + "model": "openai/gpt-4.1-mini", + "messages": [{"role": "user", "content": "Reply with OK."}], + } + ] def test_gepa_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch): @@ -473,8 +434,8 @@ def chat_completion(self, payload, stream=False): assert seen_billing_timeouts[1].read == 300.0 -@pytest.mark.parametrize("env_id_field", ["env_id", "id"]) -def test_eval_config_job_id_uses_config_env_id(monkeypatch, tmp_path, env_id_field): +@pytest.mark.parametrize("prefix", ["", "@"]) +def test_eval_config_uses_v1_taskset(monkeypatch, tmp_path, prefix): monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) @@ -487,11 +448,11 @@ def test_eval_config_job_id_uses_config_env_id(monkeypatch, tmp_path, env_id_fie config_path = tmp_path / "reverse-text.toml" config_path.write_text( - f""" + """ model = "openai/gpt-4.1-mini" -[[eval]] -{env_id_field} = "primeintellect/wordle" +[taskset] +id = "primeintellect/wordle" """.strip(), encoding="utf-8", ) @@ -509,7 +470,7 @@ def fake_run_command(command, env=None): monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run_command) run_eval_passthrough( - environment=str(config_path), + environment=f"{prefix}{config_path}", passthrough_args=[], skip_upload=True, env_path=None, @@ -517,47 +478,147 @@ def fake_run_command(command, env=None): assert prepared == [("primeintellect/wordle", "./environments")] assert commands - assert commands[0][1] == str(config_path) - assert any(arg.startswith("X-PI-Job-Id: wordle_") for arg in commands[0]), commands[0] - assert not any(arg.startswith("X-PI-Job-Id: reverse_text_") for arg in commands[0]), commands[0] + assert commands[0][1] == f"@{config_path}" + header_idx = commands[0].index("--client.headers") + headers = json.loads(commands[0][header_idx + 1]) + assert headers["X-PI-Job-Id"].startswith("wordle_openai_gpt_4.1_mini_") -def test_eval_provider_short_flag_is_not_treated_as_env_dir(monkeypatch, tmp_path): +@pytest.mark.parametrize("from_config", [False, True]) +def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_config): + monkeypatch.chdir(tmp_path) monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._validate_model", + lambda *_args: (_ for _ in ()).throw(AssertionError("dry-run must not make API calls")), + ) monkeypatch.setattr( "prime_cli.verifiers_bridge._preflight_inference_billing", - lambda *args: None, + lambda *_args: (_ for _ in ()).throw(AssertionError("dry-run must not make API calls")), + ) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_single_environment", + lambda _plugin, environment, _env_dir: ResolvedEnvironment( + original=environment, + env_name=environment, + install_mode="local", + ), + ) + captured = {} + monkeypatch.setattr( + "prime_cli.verifiers_bridge._run_command", + lambda command, env=None: captured.update(command=command), + ) + + if from_config: + config_path = tmp_path / "eval.toml" + config_path.write_text('dry_run = true\n\n[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") + environment = str(config_path) + args = [] + else: + environment = "gsm8k-v1" + args = ["--dry-run", "true"] + + run_eval_passthrough( + environment=environment, + passthrough_args=args, + skip_upload=True, + env_path=None, + ) + + assert captured["command"][0] == "verifiers.v1.cli.eval.main" + + +def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None ) + monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_single_environment", lambda *_: None) + output_dir = tmp_path / "configured-output" config_path = tmp_path / "eval.toml" config_path.write_text( - """ -[[eval]] -env_id = "wiki-search" -""".strip(), + f'output_dir = "{output_dir}"\n\n[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8", ) + captured = {} - prepared = [] - - def fake_prepare(_plugin, env_reference, env_dir_path): - prepared.append((env_reference, env_dir_path)) + def fake_run(command, env=None): + captured["command"] = command + output_dir.mkdir() + (output_dir / "results.jsonl").write_text( + json.dumps( + {"task": {"idx": 0, "prompt": None}, "nodes": [], "rewards": {"correct": 1.0}} + ) + + "\n", + encoding="utf-8", + ) - monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_single_environment", fake_prepare) - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda *args, **kwargs: None) + monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) run_eval_passthrough( environment=str(config_path), - passthrough_args=["-p", "openai"], + passthrough_args=[], + skip_upload=True, + env_path=None, + ) + + assert "--output-dir" not in captured["command"] + assert (output_dir / "metadata.json").exists() + + +def test_eval_writes_v1_metadata(monkeypatch, tmp_path): + monkeypatch.chdir(tmp_path) + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._preflight_inference_billing", + lambda *args: None, + ) + + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_single_environment", + lambda *_args: ResolvedEnvironment( + original="wiki-search", env_name="wiki-search", install_mode="local" + ), + ) + + def fake_run(command, env=None): + output_dir = Path(command[command.index("--output-dir") + 1]) + output_dir.mkdir(parents=True) + rows = [ + {"task": {"idx": 0, "prompt": None}, "nodes": [], "rewards": {"correct": 1.0}}, + {"task": {"idx": 1, "prompt": None}, "nodes": [], "rewards": {"correct": 0.5}}, + ] + (output_dir / "results.jsonl").write_text( + "".join(json.dumps(row) + "\n" for row in rows), encoding="utf-8" + ) + + monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) + + run_eval_passthrough( + environment="wiki-search", + passthrough_args=["-m", "openai/gpt-4.1-mini"], skip_upload=True, env_path=None, ) - assert prepared == [("wiki-search", "./environments")] + (metadata_path,) = tmp_path.glob("outputs/evals/*/*/metadata.json") + metadata = json.loads(metadata_path.read_text()) + assert metadata["num_examples"] == 2 + assert metadata["rollouts_per_example"] == 1 + assert metadata["avg_reward"] == 0.75 def test_inference_client_uses_custom_timeout(monkeypatch): diff --git a/packages/prime/tests/test_eval_help.py b/packages/prime/tests/test_eval_help.py index 3f84969de..1b1004718 100644 --- a/packages/prime/tests/test_eval_help.py +++ b/packages/prime/tests/test_eval_help.py @@ -1,5 +1,6 @@ from prime_cli.main import app from prime_cli.verifiers_bridge import _append_eval_options, _sanitize_help_text +from prime_cli.verifiers_plugin import PrimeVerifiersPlugin from typer.testing import CliRunner runner = CliRunner() @@ -42,6 +43,26 @@ def test_sanitize_help_removes_vf_eval_aliases(): assert "env_id_or_config" not in help_text +def test_sanitize_help_rewrites_v1_console_script(): + raw = "usage: uv run eval []\nusage: main.py [-h] [@ FILE] [OPTIONS]\n" + + help_text = _sanitize_help_text(raw, "verifiers.v1.cli.eval.main", "prime eval run") + + assert help_text.count("Usage: prime eval run") == 2 + assert "uv run eval" not in help_text + + +def test_v1_module_command_calls_console_entrypoint(monkeypatch): + monkeypatch.setattr("prime_cli.verifiers_plugin.resolve_workspace_python", lambda: "python") + plugin = PrimeVerifiersPlugin() + + command = plugin.build_module_command(plugin.eval_module, ["--help"]) + + assert command[:2] == ["python", "-c"] + assert "sys.argv[0] = 'eval'" in command[2] + assert command[-1] == "--help" + + def test_append_eval_options_mentions_tunnel_access(): help_text = _append_eval_options("Usage: prime eval run [-h] environment\n") diff --git a/packages/prime/tests/test_eval_push.py b/packages/prime/tests/test_eval_push.py index b1e20d0aa..18212f802 100644 --- a/packages/prime/tests/test_eval_push.py +++ b/packages/prime/tests/test_eval_push.py @@ -10,12 +10,70 @@ _validate_eval_path, ) from prime_cli.main import app +from prime_cli.utils.eval_push import convert_eval_results from typer.testing import CliRunner from typing_extensions import cast runner = CliRunner() +def test_convert_eval_results_supports_v1_and_legacy_samples(): + samples = [ + {"id": 3, "reward": 0.5, "completion": "legacy"}, + { + "id": "trace-1", + "task": {"idx": 7, "prompt": "What is 2 + 2?", "answer": "4"}, + "nodes": [ + { + "message": {"role": "user", "content": "What is 2 + 2?"}, + "token_ids": [1, 2], + "mask": [False, False], + }, + { + "parent": 0, + "message": {"role": "assistant", "content": "4"}, + "sampled": True, + "token_ids": [3, 4], + "mask": [False, True], + "logprobs": [-0.1], + }, + ], + "rewards": {"correct": 1.0}, + "metrics": {"exact_match": 1.0}, + "info": {"source": "test"}, + "is_completed": True, + "grader_note": "kept as metadata", + }, + ] + + legacy, v1 = convert_eval_results(samples) + + assert legacy == { + "id": 3, + "example_id": 3, + "reward": 0.5, + "completion": "legacy", + } + assert v1["sample_id"] == "trace-1" + assert v1["example_id"] == 7 + assert v1["rollout_number"] == 1 + assert v1["answer"] == "4" + assert v1["reward"] == 1.0 + assert v1["completion"][-1] == {"role": "assistant", "content": "4"} + assert v1["trajectory"] == [ + { + "messages": [ + {"role": "user", "content": "What is 2 + 2?"}, + {"role": "assistant", "content": "4"}, + ], + "reward": 1.0, + "num_input_tokens": 3, + "num_output_tokens": 1, + } + ] + assert v1["info"] == {"source": "test", "grader_note": "kept as metadata"} + + class TestHasEvalFiles: """Tests for _has_eval_files function""" diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index 148e2428d..43a3d7ae3 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -1307,8 +1307,8 @@ def test_eval_run_local_toml_passthrough(monkeypatch, tmp_path): """ model = "openai/gpt-4.1-mini" -[[eval]] -env_id = "gsm8k" +[taskset] +id = "gsm8k-v1" """.strip() ) @@ -1322,7 +1322,7 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa result = runner.invoke( app, - ["eval", "run", str(config_path), "--skip-upload"], + ["eval", "run", "@", str(config_path), "--skip-upload"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) @@ -1335,7 +1335,7 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa } -def test_eval_run_local_sampling_args_passthrough(monkeypatch): +def test_eval_run_resume_passthrough(monkeypatch, tmp_path): captured = {} def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): @@ -1345,22 +1345,82 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa captured["env_path"] = env_path monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) + output_dir = tmp_path / "previous-run" result = runner.invoke( app, - ["eval", "run", "gsm8k", "--sampling-args", '{"temperature":0.2}'], + ["eval", "run", "--resume", str(output_dir), "--skip-upload"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) assert result.exit_code == 0, result.output assert captured == { - "environment": "gsm8k", - "passthrough_args": ["--sampling-args", '{"temperature":0.2}'], + "environment": str(output_dir), + "passthrough_args": ["--resume", str(output_dir)], + "skip_upload": True, + "env_path": None, + } + + +def test_eval_run_local_v1_sampling_passthrough(monkeypatch): + captured = {} + + def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): + captured["environment"] = environment + captured["passthrough_args"] = passthrough_args + captured["skip_upload"] = skip_upload + captured["env_path"] = env_path + + monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) + + result = runner.invoke( + app, + ["eval", "run", "gsm8k-v1", "--sampling.temperature", "0.2"], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + + assert result.exit_code == 0, result.output + assert captured == { + "environment": "gsm8k-v1", + "passthrough_args": ["--sampling.temperature", "0.2"], "skip_upload": False, "env_path": None, } +def test_eval_run_legacy_sampling_args_passthrough(monkeypatch): + captured = {} + + def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): + captured["environment"] = environment + captured["passthrough_args"] = passthrough_args + + monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) + + result = runner.invoke( + app, + [ + "eval", + "run", + "legacy-env", + "--save-results", + "--sampling-args", + '{"temperature":0.2}', + ], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + + assert result.exit_code == 0, result.output + assert captured == { + "environment": "legacy-env", + "passthrough_args": [ + "--save-results", + "--sampling-args", + '{"temperature":0.2}', + ], + } + + @pytest.mark.parametrize( ("extra_args", "expected_flag"), [ From b2d2c80791e94dadd49fddb95bd1cfd4dade2649 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 11:57:17 +0200 Subject: [PATCH 02/19] update Verifiers dependency lock --- .github/workflows/ci.yml | 32 +- packages/prime/pyproject.toml | 2 +- pyproject.toml | 1 - uv.lock | 1206 ++++++++------------------------- 4 files changed, 286 insertions(+), 955 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82918c126..54d389538 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ["3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 @@ -120,14 +120,14 @@ jobs: - name: Install dependencies working-directory: packages/prime-sandboxes - run: uv pip install --system --no-config --exclude-newer "7 days" --editable ".[dev]" + run: uv sync --all-extras - name: Run tests working-directory: packages/prime-sandboxes env: PRIME_API_KEY: ${{ secrets.PRIME_API_KEY }} PRIME_TEAM_ID: ${{ secrets.PRIME_TEAM_ID }} - run: python -m pytest tests/ -v -n auto + run: uv run pytest tests/ -v -n auto test-prime: runs-on: ubuntu-latest @@ -149,23 +149,14 @@ jobs: - name: Install dependencies working-directory: packages/prime - run: | - uv sync --all-extras --frozen - uv pip install --no-config --no-sources \ - --exclude-newer "7 days" \ - --exclude-newer-package "verifiers=0 days" \ - --exclude-newer-package "prime-pydantic-config=0 days" \ - --exclude-newer-package "renderers=0 days" \ - "verifiers==0.1.15.dev371" \ - "prime-pydantic-config>=0.3.0.dev86" \ - "renderers>=0.1.8.dev40" + run: uv sync --all-extras - name: Run tests with pytest working-directory: packages/prime env: PRIME_API_KEY: ${{ secrets.PRIME_API_KEY }} PRIME_TEAM_ID: ${{ secrets.PRIME_TEAM_ID }} - run: uv run --no-sync pytest tests/ -v + run: uv run pytest tests/ -v type-check: runs-on: ubuntu-latest @@ -184,17 +175,8 @@ jobs: - name: Install dependencies working-directory: packages/prime - run: | - uv sync --all-extras --frozen - uv pip install --no-config --no-sources \ - --exclude-newer "7 days" \ - --exclude-newer-package "verifiers=0 days" \ - --exclude-newer-package "prime-pydantic-config=0 days" \ - --exclude-newer-package "renderers=0 days" \ - "verifiers==0.1.15.dev371" \ - "prime-pydantic-config>=0.3.0.dev86" \ - "renderers>=0.1.8.dev40" + run: uv sync --all-extras - name: Run ty type checker working-directory: packages/prime - run: uv run --no-sync ty check src/ + run: uv run ty check src/ diff --git a/packages/prime/pyproject.toml b/packages/prime/pyproject.toml index 31e6e56d6..29d5e0253 100644 --- a/packages/prime/pyproject.toml +++ b/packages/prime/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "textual>=6.1.0", "textual-plot>=0.10.1", "cryptography>=41.0.0", - "verifiers==0.1.15.dev371", + "verifiers>=0.1.15.dev371", "build>=1.0.0", "gitignore-parser>=0.1.13", "pyyaml>=6.0.0", diff --git a/pyproject.toml b/pyproject.toml index 73a99d314..1e44b3b38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ harnesses = false [tool.uv.sources] prime-tunnel = { workspace = true } -verifiers = { git = "https://github.com/PrimeIntellect-ai/verifiers.git", tag = "v0.1.14" } [tool.pytest.ini_options] pythonpath = [ diff --git a/uv.lock b/uv.lock index 3ca1f0ea7..5308b7644 100644 --- a/uv.lock +++ b/uv.lock @@ -1,10 +1,10 @@ version = 1 revision = 3 -requires-python = ">=3.10" +requires-python = ">=3.11, <3.14" resolution-markers = [ "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", - "python_full_version < '3.11'", + "python_full_version < '3.12'", + "python_version < '0'", ] [options] @@ -12,10 +12,12 @@ exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for exclude-newer-span = "P7D" [options.exclude-newer-package] -prime-tunnel = false -prime-sandboxes = false verifiers = false tasksets = false +prime-pydantic-config = "2099-12-31T23:00:00Z" +prime-tunnel = false +prime-sandboxes = false +renderers = "2099-12-31T23:00:00Z" harnesses = false prime-evals = false prime = false @@ -63,7 +65,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, @@ -72,23 +73,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/62/f1/8515650ac3121a9e55c7b217c60e7fae3e0134b5acfe65691781b5356929/aiohttp-3.13.0.tar.gz", hash = "sha256:378dbc57dd8cf341ce243f13fa1fa5394d68e2e02c15cd5f28eae35a70ec7f67", size = 7832348, upload-time = "2025-10-06T19:58:48.089Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/18/a3a9c9b7c8d400f71d1ff93c3e1520a5d53dba170f829ca9c6b2b070677b/aiohttp-3.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ca69ec38adf5cadcc21d0b25e2144f6a25b7db7bea7e730bac25075bc305eff0", size = 734428, upload-time = "2025-10-06T19:54:40.285Z" }, - { url = "https://files.pythonhosted.org/packages/aa/02/f1eac06d78997e015030130ccf1c7cf864a919f97d77ff27e89c82fc3186/aiohttp-3.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:240f99f88a9a6beb53ebadac79a2e3417247aa756202ed234b1dbae13d248092", size = 491939, upload-time = "2025-10-06T19:54:42.113Z" }, - { url = "https://files.pythonhosted.org/packages/e1/db/5d65af7cbe5f302e23b1ea5cfc156cd0c7738a0d2db531a3837d2754de94/aiohttp-3.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a4676b978a9711531e7cea499d4cdc0794c617a1c0579310ab46c9fdf5877702", size = 487229, upload-time = "2025-10-06T19:54:43.978Z" }, - { url = "https://files.pythonhosted.org/packages/d3/d5/56c622ad3bd57ff4adc2b701f298dcc0408735a8af998cec1c66a9ce224e/aiohttp-3.13.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48fcdd5bc771cbbab8ccc9588b8b6447f6a30f9fe00898b1a5107098e00d6793", size = 1666118, upload-time = "2025-10-06T19:54:46.569Z" }, - { url = "https://files.pythonhosted.org/packages/44/16/db236671ec3758e3a6be6977009e74016470368012a58fea4b3799546549/aiohttp-3.13.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eeea0cdd2f687e210c8f605f322d7b0300ba55145014a5dbe98bd4be6fff1f6c", size = 1633983, upload-time = "2025-10-06T19:54:48.244Z" }, - { url = "https://files.pythonhosted.org/packages/19/ad/d96d7d7023e7f5215b8737cad21a7637f6d9d10fbfbfef0435d0277f71a2/aiohttp-3.13.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b3f01d5aeb632adaaf39c5e93f040a550464a768d54c514050c635adcbb9d0", size = 1725922, upload-time = "2025-10-06T19:54:49.885Z" }, - { url = "https://files.pythonhosted.org/packages/88/d7/e8a5ba2bbd929ed587b2a8ea9390765daede2d8cd28dfae3a0773c6d3fbc/aiohttp-3.13.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a4dc0b83e25267f42ef065ea57653de4365b56d7bc4e4cfc94fabe56998f8ee6", size = 1813770, upload-time = "2025-10-06T19:54:51.648Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ca/135c21e85ffeff66b80ecd8a647ca104f2e5a91c37dc86649244ddbf87ab/aiohttp-3.13.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:72714919ed9b90f030f761c20670e529c4af96c31bd000917dd0c9afd1afb731", size = 1667322, upload-time = "2025-10-06T19:54:53.668Z" }, - { url = "https://files.pythonhosted.org/packages/f6/38/348c4343052a400968dbf2051ee3dc222bdefd95af5874cf0f04cc7a8c92/aiohttp-3.13.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:564be41e85318403fdb176e9e5b3e852d528392f42f2c1d1efcbeeed481126d7", size = 1553270, upload-time = "2025-10-06T19:54:56.054Z" }, - { url = "https://files.pythonhosted.org/packages/47/89/71cbda30f0900ab16084769960c467a355d6b1db51668fbb821c4a4ad5ed/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:84912962071087286333f70569362e10793f73f45c48854e6859df11001eb2d3", size = 1637087, upload-time = "2025-10-06T19:54:58.548Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/5ff5fcaecccdcd5be7ff717cbde6e630760a8130e89167c3aa05b6b57707/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:90b570f1a146181c3d6ae8f755de66227ded49d30d050479b5ae07710f7894c5", size = 1643443, upload-time = "2025-10-06T19:55:00.856Z" }, - { url = "https://files.pythonhosted.org/packages/87/e2/1d1f202f43c8be1956f05196159064cc05dc6842a33c1397cbb1b99610af/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2d71ca30257ce756e37a6078b1dff2d9475fee13609ad831eac9a6531bea903b", size = 1695571, upload-time = "2025-10-06T19:55:03.006Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b9/53c1df2991686f947a9651265757ea12c4afc29b351a249b73a0fc81dd3c/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:cd45eb70eca63f41bb156b7dffbe1a7760153b69892d923bdb79a74099e2ed90", size = 1539975, upload-time = "2025-10-06T19:55:04.839Z" }, - { url = "https://files.pythonhosted.org/packages/93/24/345166f9c4cd2f5cc1d2173131998ee4adab0db8729126db32a7f91ed400/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5ae3a19949a27982c7425a7a5a963c1268fdbabf0be15ab59448cbcf0f992519", size = 1712866, upload-time = "2025-10-06T19:55:06.905Z" }, - { url = "https://files.pythonhosted.org/packages/09/f1/e8f70462848b74d49b3115050623ecbd697889713c2c93c96616da56b2de/aiohttp-3.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ea6df292013c9f050cbf3f93eee9953d6e5acd9e64a0bf4ca16404bfd7aa9bcc", size = 1654058, upload-time = "2025-10-06T19:55:08.51Z" }, - { url = "https://files.pythonhosted.org/packages/23/ba/47fd065510a8bfab5d5f6e1d97c0de672447c0a941c5021298bd7210afc3/aiohttp-3.13.0-cp310-cp310-win32.whl", hash = "sha256:3b64f22fbb6dcd5663de5ef2d847a5638646ef99112503e6f7704bdecb0d1c4d", size = 430230, upload-time = "2025-10-06T19:55:10.178Z" }, - { url = "https://files.pythonhosted.org/packages/c4/38/f5385cb79afa1f31bcaa3625a9e8d849b782edaeac09f894f46439e006a1/aiohttp-3.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:f8d877aa60d80715b2afc565f0f1aea66565824c229a2d065b31670e09fed6d7", size = 453013, upload-time = "2025-10-06T19:55:11.623Z" }, { url = "https://files.pythonhosted.org/packages/b1/db/df80cacac46cd548a736c5535b13cc18925cf6f9f83cd128cf3839842219/aiohttp-3.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:99eb94e97a42367fef5fc11e28cb2362809d3e70837f6e60557816c7106e2e20", size = 741374, upload-time = "2025-10-06T19:55:13.095Z" }, { url = "https://files.pythonhosted.org/packages/ae/f9/2d6d93fd57ab4726e18a7cdab083772eda8302d682620fbf2aef48322351/aiohttp-3.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4696665b2713021c6eba3e2b882a86013763b442577fe5d2056a42111e732eca", size = 494956, upload-time = "2025-10-06T19:55:14.687Z" }, { url = "https://files.pythonhosted.org/packages/89/a6/e1c061b079fed04ffd6777950c82f2e8246fd08b7b3c4f56fdd47f697e5a/aiohttp-3.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e6a38366f7f0d0f6ed7a1198055150c52fda552b107dad4785c0852ad7685d1", size = 491154, upload-time = "2025-10-06T19:55:16.661Z" }, @@ -140,40 +124,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/e7/cc9f0fdf06cab3ca61e6b62bff9a4b978b8ca736e9d76ddf54365673ab19/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:582770f82513419512da096e8df21ca44f86a2e56e25dc93c5ab4df0fe065bf0", size = 1714933, upload-time = "2025-10-06T19:56:45.542Z" }, { url = "https://files.pythonhosted.org/packages/db/43/7abbe1de94748a58a71881163ee280fd3217db36e8344d109f63638fe16a/aiohttp-3.13.0-cp313-cp313-win32.whl", hash = "sha256:3194b8cab8dbc882f37c13ef1262e0a3d62064fa97533d3aa124771f7bf1ecee", size = 423799, upload-time = "2025-10-06T19:56:47.779Z" }, { url = "https://files.pythonhosted.org/packages/c9/58/afab7f2b9e7df88c995995172eb78cae8a3d5a62d5681abaade86b3f0089/aiohttp-3.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:7897298b3eedc790257fef8a6ec582ca04e9dbe568ba4a9a890913b925b8ea21", size = 450138, upload-time = "2025-10-06T19:56:49.49Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c1/93bb1e35cd0c4665bb422b1ca3d87b588f4bca2656bbe9292b963d5b76a9/aiohttp-3.13.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c417f8c2e1137775569297c584a8a7144e5d1237789eae56af4faf1894a0b861", size = 733187, upload-time = "2025-10-06T19:56:51.385Z" }, - { url = "https://files.pythonhosted.org/packages/5e/36/2d50eba91992d3fe7a6452506ccdab45d03685ee8d8acaa5b289384a7d4c/aiohttp-3.13.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f84b53326abf8e56ebc28a35cebf4a0f396a13a76300f500ab11fe0573bf0b52", size = 488684, upload-time = "2025-10-06T19:56:53.25Z" }, - { url = "https://files.pythonhosted.org/packages/82/93/fa4b1d5ecdc7805bdf0815ef00257db4632ccf0a8bffd44f9fc4657b1677/aiohttp-3.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:990a53b9d6a30b2878789e490758e568b12b4a7fb2527d0c89deb9650b0e5813", size = 489255, upload-time = "2025-10-06T19:56:55.136Z" }, - { url = "https://files.pythonhosted.org/packages/05/0f/85241f0d158da5e24e8ac9d50c0849ed24f882cafc53dc95749ef85eef09/aiohttp-3.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c811612711e01b901e18964b3e5dec0d35525150f5f3f85d0aee2935f059910a", size = 1715914, upload-time = "2025-10-06T19:56:57.286Z" }, - { url = "https://files.pythonhosted.org/packages/ab/fc/c755590d6f6d2b5d1565c72d6ee658d3c30ec61acb18964d1e9bf991d9b5/aiohttp-3.13.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee433e594d7948e760b5c2a78cc06ac219df33b0848793cf9513d486a9f90a52", size = 1665171, upload-time = "2025-10-06T19:56:59.688Z" }, - { url = "https://files.pythonhosted.org/packages/3a/de/caa61e213ff546b8815aef5e931d7eae1dbe8c840a3f11ec5aa41c5ae462/aiohttp-3.13.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:19bb08e56f57c215e9572cd65cb6f8097804412c54081d933997ddde3e5ac579", size = 1755124, upload-time = "2025-10-06T19:57:02.69Z" }, - { url = "https://files.pythonhosted.org/packages/fb/b7/40c3219dd2691aa35cf889b4fbb0c00e48a19092928707044bfe92068e01/aiohttp-3.13.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f27b7488144eb5dd9151cf839b195edd1569629d90ace4c5b6b18e4e75d1e63a", size = 1835949, upload-time = "2025-10-06T19:57:05.251Z" }, - { url = "https://files.pythonhosted.org/packages/57/e8/66e3c32841fc0e26a09539c377aa0f3bbf6deac1957ac5182cf276c5719c/aiohttp-3.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d812838c109757a11354a161c95708ae4199c4fd4d82b90959b20914c1d097f6", size = 1714276, upload-time = "2025-10-06T19:57:07.41Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a5/c68e5b46ff0410fe3abfa508651b09372428f27036138beacf4ff6b7cb8c/aiohttp-3.13.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7c20db99da682f9180fa5195c90b80b159632fb611e8dbccdd99ba0be0970620", size = 1545929, upload-time = "2025-10-06T19:57:09.336Z" }, - { url = "https://files.pythonhosted.org/packages/7a/a6/4c97dc27f9935c0c0aa6e3e10e5b4548823ab5d056636bde374fcd297256/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cf8b0870047900eb1f17f453b4b3953b8ffbf203ef56c2f346780ff930a4d430", size = 1679988, upload-time = "2025-10-06T19:57:11.367Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1b/11f9c52fd72b786a47e796e6794883417280cdca8eb1032d8d0939928dfa/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b8a5557d5af3f4e3add52a58c4cf2b8e6e59fc56b261768866f5337872d596d", size = 1678031, upload-time = "2025-10-06T19:57:13.357Z" }, - { url = "https://files.pythonhosted.org/packages/ea/eb/948903d40505f3a25e53e051488d2714ded3afac1f961df135f2936680f9/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:052bcdd80c1c54b8a18a9ea0cd5e36f473dc8e38d51b804cea34841f677a9971", size = 1726184, upload-time = "2025-10-06T19:57:15.478Z" }, - { url = "https://files.pythonhosted.org/packages/44/14/c8ced38c7dfe80804dec17a671963ccf3cb282f12700ec70b1f689d8de7d/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:76484ba17b2832776581b7ab466d094e48eba74cb65a60aea20154dae485e8bd", size = 1542344, upload-time = "2025-10-06T19:57:17.611Z" }, - { url = "https://files.pythonhosted.org/packages/a4/6e/f2e6bff550a51fd7c45fdab116a1dab7cc502e5d942956f10fc5c626bb15/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:62d8a0adcdaf62ee56bfb37737153251ac8e4b27845b3ca065862fb01d99e247", size = 1740913, upload-time = "2025-10-06T19:57:19.821Z" }, - { url = "https://files.pythonhosted.org/packages/da/00/8f057300d9b598a706348abb375b3de9a253195fb615f17c0b2be2a72836/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5004d727499ecb95f7c9147dd0bfc5b5670f71d355f0bd26d7af2d3af8e07d2f", size = 1695535, upload-time = "2025-10-06T19:57:21.856Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ab/6919d584d8f053a14b15f0bfa3f315b3f548435c2142145459da2efa8673/aiohttp-3.13.0-cp314-cp314-win32.whl", hash = "sha256:a1c20c26af48aea984f63f96e5d7af7567c32cb527e33b60a0ef0a6313cf8b03", size = 429548, upload-time = "2025-10-06T19:57:24.285Z" }, - { url = "https://files.pythonhosted.org/packages/c5/59/5d9e78de6132079066f5077d9687bf524f764a2f8207e04d8d68790060c6/aiohttp-3.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:56f7d230ec66e799fbfd8350e9544f8a45a4353f1cf40c1fea74c1780f555b8f", size = 455548, upload-time = "2025-10-06T19:57:26.136Z" }, - { url = "https://files.pythonhosted.org/packages/7c/ea/7d98da03d1e9798bb99c3ca4963229150d45c9b7a3a16210c5b4a5f89e07/aiohttp-3.13.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:2fd35177dc483ae702f07b86c782f4f4b100a8ce4e7c5778cea016979023d9fd", size = 765319, upload-time = "2025-10-06T19:57:28.278Z" }, - { url = "https://files.pythonhosted.org/packages/5c/02/37f29beced8213bb467c52ad509a5e3b41e6e967de2f6eaf7f8db63bea54/aiohttp-3.13.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4df1984c8804ed336089e88ac81a9417b1fd0db7c6f867c50a9264488797e778", size = 502567, upload-time = "2025-10-06T19:57:30.273Z" }, - { url = "https://files.pythonhosted.org/packages/e7/22/b0afcafcfe3637bc8d7992abf08ee9452018366c0801e4e7d4efda2ed839/aiohttp-3.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e68c0076052dd911a81d3acc4ef2911cc4ef65bf7cadbfbc8ae762da24da858f", size = 507078, upload-time = "2025-10-06T19:57:32.619Z" }, - { url = "https://files.pythonhosted.org/packages/49/4c/046c847b7a1993b49f3855cc3b97872d5df193d9240de835d0dc6a97b164/aiohttp-3.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc95c49853cd29613e4fe4ff96d73068ff89b89d61e53988442e127e8da8e7ba", size = 1862115, upload-time = "2025-10-06T19:57:34.758Z" }, - { url = "https://files.pythonhosted.org/packages/1a/25/1449a59e3c6405da5e47b0138ee0855414dc12a8c306685d7fc3dd300e1f/aiohttp-3.13.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3b3bdc89413117b40cc39baae08fd09cbdeb839d421c4e7dce6a34f6b54b3ac1", size = 1717147, upload-time = "2025-10-06T19:57:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/23/8f/50cc34ad267b38608f21c6a74327015dd08a66f1dd8e7ceac954d0953191/aiohttp-3.13.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e77a729df23be2116acc4e9de2767d8e92445fbca68886dd991dc912f473755", size = 1841443, upload-time = "2025-10-06T19:57:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/df/b9/b3ab1278faa0d1b8f434c85f9cf34eeb0a25016ffe1ee6bc361d09fef0ec/aiohttp-3.13.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e88ab34826d6eeb6c67e6e92400b9ec653faf5092a35f07465f44c9f1c429f82", size = 1933652, upload-time = "2025-10-06T19:57:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/88/e2/86050aaa3bd7021b115cdfc88477b754e8cf93ef0079867840eee22d3c34/aiohttp-3.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:019dbef24fe28ce2301419dd63a2b97250d9760ca63ee2976c2da2e3f182f82e", size = 1790682, upload-time = "2025-10-06T19:57:44.851Z" }, - { url = "https://files.pythonhosted.org/packages/78/8d/9af903324c2ba24a0c4778e9bcc738b773c98dded3a4fcf8041d5211769f/aiohttp-3.13.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2c4aeaedd20771b7b4bcdf0ae791904445df6d856c02fc51d809d12d17cffdc7", size = 1622011, upload-time = "2025-10-06T19:57:47.025Z" }, - { url = "https://files.pythonhosted.org/packages/84/97/5174971ba4986d913554ceb248b0401eb5358cb60672ea0166f9f596cd08/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b3a8e6a2058a0240cfde542b641d0e78b594311bc1a710cbcb2e1841417d5cb3", size = 1787148, upload-time = "2025-10-06T19:57:49.149Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ae/8b397e980ac613ef3ddd8e996aa7a40a1828df958257800d4bb325657db3/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8e38d55ca36c15f36d814ea414ecb2401d860de177c49f84a327a25b3ee752b", size = 1774816, upload-time = "2025-10-06T19:57:51.523Z" }, - { url = "https://files.pythonhosted.org/packages/c7/54/0e8e2111dd92051c787e934b6bbf30c213daaa5e7ee5f51bca8913607492/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a921edbe971aade1bf45bcbb3494e30ba6863a5c78f28be992c42de980fd9108", size = 1788610, upload-time = "2025-10-06T19:57:54.337Z" }, - { url = "https://files.pythonhosted.org/packages/fa/dd/c9283dbfd9325ed6fa6c91f009db6344d8d370a7bcf09f36e7b2fcbfae02/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:474cade59a447cb4019c0dce9f0434bf835fb558ea932f62c686fe07fe6db6a1", size = 1615498, upload-time = "2025-10-06T19:57:56.604Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f6/da76230679bd9ef175d876093f89e7fd6d6476c18505e115e3026fe5ef95/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:99a303ad960747c33b65b1cb65d01a62ac73fa39b72f08a2e1efa832529b01ed", size = 1815187, upload-time = "2025-10-06T19:57:59.036Z" }, - { url = "https://files.pythonhosted.org/packages/d5/78/394003ac738703822616f4f922705b54e5b3d8e7185831ecc1c97904174d/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bb34001fc1f05f6b323e02c278090c07a47645caae3aa77ed7ed8a3ce6abcce9", size = 1760281, upload-time = "2025-10-06T19:58:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/bd/b0/4bad0a9dd5910bd01c3119f8bd3d71887cd412d4105e4acddcdacf3cfa76/aiohttp-3.13.0-cp314-cp314t-win32.whl", hash = "sha256:dea698b64235d053def7d2f08af9302a69fcd760d1c7bd9988fd5d3b6157e657", size = 462608, upload-time = "2025-10-06T19:58:03.674Z" }, - { url = "https://files.pythonhosted.org/packages/bd/af/ad12d592f623aae2bd1d3463201dc39c201ea362f9ddee0d03efd9e83720/aiohttp-3.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1f164699a060c0b3616459d13c1464a981fddf36f892f0a5027cbd45121fb14b", size = 496010, upload-time = "2025-10-06T19:58:05.589Z" }, ] [[package]] @@ -240,7 +190,6 @@ name = "anyio" version = "4.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -250,15 +199,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, ] -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - [[package]] name = "attrs" version = "25.4.0" @@ -268,25 +208,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] -[[package]] -name = "backports-asyncio-runner" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, -] - [[package]] name = "build" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "os_name == 'nt'" }, - { name = "importlib-metadata", marker = "python_full_version < '3.10.2'" }, { name = "packaging" }, { name = "pyproject-hooks" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/1c/23e33405a7c9eac261dff640926b8b5adaed6a6eb3e1767d441ed611d0c0/build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397", size = 48544, upload-time = "2025-08-01T21:27:09.268Z" } wheels = [ @@ -311,18 +240,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, @@ -360,28 +277,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, ] [[package]] @@ -399,17 +294,6 @@ 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/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, - { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, - { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, - { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, - { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, - { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, - { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, - { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, - { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, @@ -443,17 +327,6 @@ wheels = [ { 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" }, ] @@ -497,7 +370,6 @@ version = "46.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4a/9b/e301418629f7bfdf72db9e80ad6ed9d1b83c487c471803eaa6464c511a01/cryptography-46.0.2.tar.gz", hash = "sha256:21b6fc8c71a3f9a604f028a329e5560009cc4a3a828bfea5fcba8eb7647d88fe", size = 749293, upload-time = "2025-10-01T00:29:11.856Z" } wheels = [ @@ -516,21 +388,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/2b/531e37408573e1da33adfb4c58875013ee8ac7d548d1548967d94a0ae5c4/cryptography-46.0.2-cp311-abi3-win32.whl", hash = "sha256:8b9bf67b11ef9e28f4d78ff88b04ed0929fcd0e4f70bb0f704cfc32a5c6311ee", size = 3056077, upload-time = "2025-10-01T00:27:48.424Z" }, { url = "https://files.pythonhosted.org/packages/a8/cd/2f83cafd47ed2dc5a3a9c783ff5d764e9e70d3a160e0df9a9dcd639414ce/cryptography-46.0.2-cp311-abi3-win_amd64.whl", hash = "sha256:758cfc7f4c38c5c5274b55a57ef1910107436f4ae842478c4989abbd24bd5acb", size = 3512585, upload-time = "2025-10-01T00:27:50.521Z" }, { url = "https://files.pythonhosted.org/packages/00/36/676f94e10bfaa5c5b86c469ff46d3e0663c5dc89542f7afbadac241a3ee4/cryptography-46.0.2-cp311-abi3-win_arm64.whl", hash = "sha256:218abd64a2e72f8472c2102febb596793347a3e65fafbb4ad50519969da44470", size = 2927474, upload-time = "2025-10-01T00:27:52.91Z" }, - { url = "https://files.pythonhosted.org/packages/6f/cc/47fc6223a341f26d103cb6da2216805e08a37d3b52bee7f3b2aee8066f95/cryptography-46.0.2-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:bda55e8dbe8533937956c996beaa20266a8eca3570402e52ae52ed60de1faca8", size = 7198626, upload-time = "2025-10-01T00:27:54.8Z" }, - { url = "https://files.pythonhosted.org/packages/93/22/d66a8591207c28bbe4ac7afa25c4656dc19dc0db29a219f9809205639ede/cryptography-46.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7155c0b004e936d381b15425273aee1cebc94f879c0ce82b0d7fecbf755d53a", size = 4287584, upload-time = "2025-10-01T00:27:57.018Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3e/fac3ab6302b928e0398c269eddab5978e6c1c50b2b77bb5365ffa8633b37/cryptography-46.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a61c154cc5488272a6c4b86e8d5beff4639cdb173d75325ce464d723cda0052b", size = 4433796, upload-time = "2025-10-01T00:27:58.631Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d8/24392e5d3c58e2d83f98fe5a2322ae343360ec5b5b93fe18bc52e47298f5/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:9ec3f2e2173f36a9679d3b06d3d01121ab9b57c979de1e6a244b98d51fea1b20", size = 4292126, upload-time = "2025-10-01T00:28:00.643Z" }, - { url = "https://files.pythonhosted.org/packages/ed/38/3d9f9359b84c16c49a5a336ee8be8d322072a09fac17e737f3bb11f1ce64/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2fafb6aa24e702bbf74de4cb23bfa2c3beb7ab7683a299062b69724c92e0fa73", size = 3993056, upload-time = "2025-10-01T00:28:02.8Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a3/4c44fce0d49a4703cc94bfbe705adebf7ab36efe978053742957bc7ec324/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0c7ffe8c9b1fcbb07a26d7c9fa5e857c2fe80d72d7b9e0353dcf1d2180ae60ee", size = 4967604, upload-time = "2025-10-01T00:28:04.783Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c2/49d73218747c8cac16bb8318a5513fde3129e06a018af3bc4dc722aa4a98/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:5840f05518caa86b09d23f8b9405a7b6d5400085aa14a72a98fdf5cf1568c0d2", size = 4465367, upload-time = "2025-10-01T00:28:06.864Z" }, - { url = "https://files.pythonhosted.org/packages/1b/64/9afa7d2ee742f55ca6285a54386ed2778556a4ed8871571cb1c1bfd8db9e/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:27c53b4f6a682a1b645fbf1cd5058c72cf2f5aeba7d74314c36838c7cbc06e0f", size = 4291678, upload-time = "2025-10-01T00:28:08.982Z" }, - { url = "https://files.pythonhosted.org/packages/50/48/1696d5ea9623a7b72ace87608f6899ca3c331709ac7ebf80740abb8ac673/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:512c0250065e0a6b286b2db4bbcc2e67d810acd53eb81733e71314340366279e", size = 4931366, upload-time = "2025-10-01T00:28:10.74Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3c/9dfc778401a334db3b24435ee0733dd005aefb74afe036e2d154547cb917/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:07c0eb6657c0e9cca5891f4e35081dbf985c8131825e21d99b4f440a8f496f36", size = 4464738, upload-time = "2025-10-01T00:28:12.491Z" }, - { url = "https://files.pythonhosted.org/packages/dc/b1/abcde62072b8f3fd414e191a6238ce55a0050e9738090dc6cded24c12036/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48b983089378f50cba258f7f7aa28198c3f6e13e607eaf10472c26320332ca9a", size = 4419305, upload-time = "2025-10-01T00:28:14.145Z" }, - { url = "https://files.pythonhosted.org/packages/c7/1f/3d2228492f9391395ca34c677e8f2571fb5370fe13dc48c1014f8c509864/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e6f6775eaaa08c0eec73e301f7592f4367ccde5e4e4df8e58320f2ebf161ea2c", size = 4681201, upload-time = "2025-10-01T00:28:15.951Z" }, - { url = "https://files.pythonhosted.org/packages/de/77/b687745804a93a55054f391528fcfc76c3d6bfd082ce9fb62c12f0d29fc1/cryptography-46.0.2-cp314-cp314t-win32.whl", hash = "sha256:e8633996579961f9b5a3008683344c2558d38420029d3c0bc7ff77c17949a4e1", size = 3022492, upload-time = "2025-10-01T00:28:17.643Z" }, - { url = "https://files.pythonhosted.org/packages/60/a5/8d498ef2996e583de0bef1dcc5e70186376f00883ae27bf2133f490adf21/cryptography-46.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:48c01988ecbb32979bb98731f5c2b2f79042a6c58cc9a319c8c2f9987c7f68f9", size = 3496215, upload-time = "2025-10-01T00:28:19.272Z" }, - { url = "https://files.pythonhosted.org/packages/56/db/ee67aaef459a2706bc302b15889a1a8126ebe66877bab1487ae6ad00f33d/cryptography-46.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:8e2ad4d1a5899b7caa3a450e33ee2734be7cc0689010964703a7c4bcc8dd4fd0", size = 2919255, upload-time = "2025-10-01T00:28:21.115Z" }, { url = "https://files.pythonhosted.org/packages/d5/bb/fa95abcf147a1b0bb94d95f53fbb09da77b24c776c5d87d36f3d94521d2c/cryptography-46.0.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a08e7401a94c002e79dc3bc5231b6558cd4b2280ee525c4673f650a37e2c7685", size = 7248090, upload-time = "2025-10-01T00:28:22.846Z" }, { url = "https://files.pythonhosted.org/packages/b7/66/f42071ce0e3ffbfa80a88feadb209c779fda92a23fbc1e14f74ebf72ef6b/cryptography-46.0.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d30bc11d35743bf4ddf76674a0a369ec8a21f87aaa09b0661b04c5f6c46e8d7b", size = 4293123, upload-time = "2025-10-01T00:28:25.072Z" }, { url = "https://files.pythonhosted.org/packages/a8/5d/1fdbd2e5c1ba822828d250e5a966622ef00185e476d1cd2726b6dd135e53/cryptography-46.0.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bca3f0ce67e5a2a2cf524e86f44697c4323a86e0fd7ba857de1c30d52c11ede1", size = 4439524, upload-time = "2025-10-01T00:28:26.808Z" }, @@ -546,8 +403,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/52/ea7e2b1910f547baed566c866fbb86de2402e501a89ecb4871ea7f169a81/cryptography-46.0.2-cp38-abi3-win32.whl", hash = "sha256:0b507c8e033307e37af61cb9f7159b416173bdf5b41d11c4df2e499a1d8e007c", size = 3036711, upload-time = "2025-10-01T00:28:47.096Z" }, { url = "https://files.pythonhosted.org/packages/71/9e/171f40f9c70a873e73c2efcdbe91e1d4b1777a03398fa1c4af3c56a2477a/cryptography-46.0.2-cp38-abi3-win_amd64.whl", hash = "sha256:f9b2dc7668418fb6f221e4bf701f716e05e8eadb4f1988a2487b11aedf8abe62", size = 3500007, upload-time = "2025-10-01T00:28:48.967Z" }, { url = "https://files.pythonhosted.org/packages/3e/7c/15ad426257615f9be8caf7f97990cf3dcbb5b8dd7ed7e0db581a1c4759dd/cryptography-46.0.2-cp38-abi3-win_arm64.whl", hash = "sha256:91447f2b17e83c9e0c89f133119d83f94ce6e0fb55dd47da0a959316e6e9cfa1", size = 2918153, upload-time = "2025-10-01T00:28:51.003Z" }, - { url = "https://files.pythonhosted.org/packages/25/b2/067a7db693488f19777ecf73f925bcb6a3efa2eae42355bafaafa37a6588/cryptography-46.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f25a41f5b34b371a06dad3f01799706631331adc7d6c05253f5bca22068c7a34", size = 3701860, upload-time = "2025-10-01T00:28:53.003Z" }, - { url = "https://files.pythonhosted.org/packages/87/12/47c2aab2c285f97c71a791169529dbb89f48fc12e5f62bb6525c3927a1a2/cryptography-46.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e12b61e0b86611e3f4c1756686d9086c1d36e6fd15326f5658112ad1f1cc8807", size = 3429917, upload-time = "2025-10-01T00:28:55.03Z" }, { url = "https://files.pythonhosted.org/packages/b7/8c/1aabe338149a7d0f52c3e30f2880b20027ca2a485316756ed6f000462db3/cryptography-46.0.2-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1d3b3edd145953832e09607986f2bd86f85d1dc9c48ced41808b18009d9f30e5", size = 3714495, upload-time = "2025-10-01T00:28:57.222Z" }, { url = "https://files.pythonhosted.org/packages/e3/0a/0d10eb970fe3e57da9e9ddcfd9464c76f42baf7b3d0db4a782d6746f788f/cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fe245cf4a73c20592f0f48da39748b3513db114465be78f0a36da847221bd1b4", size = 4243379, upload-time = "2025-10-01T00:28:58.989Z" }, { url = "https://files.pythonhosted.org/packages/7d/60/e274b4d41a9eb82538b39950a74ef06e9e4d723cb998044635d9deb1b435/cryptography-46.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2b9cad9cf71d0c45566624ff76654e9bae5f8a25970c250a26ccfc73f8553e2d", size = 4409533, upload-time = "2025-10-01T00:29:00.785Z" }, @@ -567,8 +422,7 @@ dependencies = [ { name = "httpx" }, { name = "huggingface-hub" }, { name = "multiprocess" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "packaging" }, { name = "pandas" }, { name = "pyarrow" }, @@ -619,24 +473,41 @@ wheels = [ ] [[package]] -name = "exceptiongroup" -version = "1.3.0" +name = "execnet" +version = "2.1.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524, upload-time = "2024-04-08T09:04:19.245Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612, upload-time = "2024-04-08T09:04:17.414Z" }, ] [[package]] -name = "execnet" -version = "2.1.1" +name = "fastokens" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524, upload-time = "2024-04-08T09:04:19.245Z" } +sdist = { url = "https://files.pythonhosted.org/packages/14/8e/7e88ec1d48db5a6e8d8d44318ce285e38c04b81508bdc2a60e17045a116f/fastokens-0.2.0.tar.gz", hash = "sha256:ef0e175de5c8cb1b616b3210d75dce1fab78e35fc02f77f03f7847d4678be686", size = 675822, upload-time = "2026-05-17T10:32:55.642Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612, upload-time = "2024-04-08T09:04:17.414Z" }, + { url = "https://files.pythonhosted.org/packages/e8/14/3d640cbe3c866ee6c113ea4ca37c16c5aa44be6412918928bbd3f3b739ef/fastokens-0.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:e7db86c2785a502e3cd993c7d3a91c46e2751f94d1f446caa9600e9cf3dafbd1", size = 3078350, upload-time = "2026-05-17T10:32:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/bc/bf/33ca3798842fb8bdacf03a97c874454d50fe328d44e0d3c3ba7a633fd3ab/fastokens-0.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa8dcbc6ad3f7a7e9f5bf1ef3cfc9f0c04f0c8779be9e38864815dc567b27de4", size = 2983397, upload-time = "2026-05-17T10:32:38.823Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0a/1bfd13fb855bce3ce50faa644d6e0e19343035706c2628e17da1247bbf50/fastokens-0.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b399600ae5beaa34e45afd05c6835b8569861955dfdc3e05afba25fe414e5a", size = 3309835, upload-time = "2026-05-17T10:32:33.427Z" }, + { url = "https://files.pythonhosted.org/packages/32/ce/33292977a81011ffc59cee1c20b6f8d0dbd9cb39209c327dc74dc542178d/fastokens-0.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f363b1e89fe4ed979224c326b25b33b28e1172134f3e7959238276170f12328e", size = 3615173, upload-time = "2026-05-17T10:32:30.898Z" }, + { url = "https://files.pythonhosted.org/packages/07/1c/1bef8b4831bf9220ae182fcee3e250273b7f537c81aec96041f6eb4bc990/fastokens-0.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d79358faa11658d8908fbdfab321b6ae6a0ff52ae3cdce7a0fda5c30629a276", size = 3295485, upload-time = "2026-05-17T10:32:36.109Z" }, + { url = "https://files.pythonhosted.org/packages/92/11/49afb739800b6a82af04fa1e991b68669c789ebeaa3bcbc96c2544c8ff9c/fastokens-0.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cf6ae284b70d65989548a8143e1f463f31126f5650ad45ce6af05b83e4afb3e7", size = 3329524, upload-time = "2026-05-17T10:32:44.607Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d2/f9b1c01535a0ce994d30e86cf49616023246134d2a406b74c5dd49df7825/fastokens-0.2.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:40fa091ff12aa8ac00fa8e2133c7256b96209827b88de5120eb1361600d7f68f", size = 3149194, upload-time = "2026-05-17T10:32:47.596Z" }, + { url = "https://files.pythonhosted.org/packages/bd/0b/95b2e5d25efc684988918658c90445e0e5f1dc4fee7dae5edd586b4feaba/fastokens-0.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f643f4739b20c86ed21e2c46e7fe203e6a621e21124074f138819423882e3aba", size = 3401011, upload-time = "2026-05-17T10:32:50.13Z" }, + { url = "https://files.pythonhosted.org/packages/9b/31/80b74196524d7a9576fa96685a39ee1f333ffd12eb29dbeb5e65c6e3dcb2/fastokens-0.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3cd4effdc6610cbee0be717032652a1997976f1a2f21949435d925c7982cf6f3", size = 3593240, upload-time = "2026-05-17T10:32:52.661Z" }, + { url = "https://files.pythonhosted.org/packages/59/96/12814aa955b7277adb07a8b36176181f247f3b9cf973d05b34294df6a72c/fastokens-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d29eb1d608977d63fc4679d6ce2b360fdb8b0ea8d66a0eaf804f7ac31ba52a3a", size = 3089011, upload-time = "2026-05-17T10:32:43.16Z" }, + { url = "https://files.pythonhosted.org/packages/c0/05/553b59c6a8542ad7d443306fc1fd7bb012e4aae459ccf9ab422ea4c681b7/fastokens-0.2.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f8ec7a20322aafe245201727c7a507b87333c51dc580940b9ee5456dbfe3963c", size = 2992964, upload-time = "2026-05-17T10:32:39.992Z" }, + { url = "https://files.pythonhosted.org/packages/13/66/a53c2309003510de7c189ba8a9d2ea5a1833e9b447d9f69b95449c3dfe34/fastokens-0.2.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc4c0a25726620b1cc4cfb7e9dc1a53b17bbe3f2f9adbaa57b8375b5f36ac5d4", size = 3316289, upload-time = "2026-05-17T10:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/b4/54/e0e4318ee1ad0b5196df72cf93615bba0b81f7869d659a44ccc475969151/fastokens-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:160253f8d30747cf66e7ed895c513e16f7b173dd9e644fa641e2eecbd43a616a", size = 3303534, upload-time = "2026-05-17T10:32:37.462Z" }, + { url = "https://files.pythonhosted.org/packages/64/44/bfff90e4b1a43c17edf7305dafbd56dc992bbe832cc08da78f1f50104c2d/fastokens-0.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b61b9fe5b41e0bb36ad86e7551dc53293c9833909ef07b1cdbaa2055b06c3b3e", size = 3254096, upload-time = "2026-05-17T10:32:28.489Z" }, + { url = "https://files.pythonhosted.org/packages/df/89/bec1a0368100c5f1134ab1ce588d71f88697fadbbad5f26bb130eda00fe8/fastokens-0.2.0-cp39-abi3-manylinux_2_28_armv7l.whl", hash = "sha256:8f138fc64e355589be43068e6996ac0bfcfd872cd75fb5793d11d06cb9c0ac9b", size = 3000177, upload-time = "2026-05-17T10:32:29.745Z" }, + { url = "https://files.pythonhosted.org/packages/f2/fd/cbe8a033e2ef565ce5aef4e02316054b04adad96ee9805cba74a50a84ed9/fastokens-0.2.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:c1a6cd93d16e880d81deb12519cc2eb20149d7423321cf00a34ce25ea9c9ef15", size = 3626561, upload-time = "2026-05-17T10:32:32.087Z" }, + { url = "https://files.pythonhosted.org/packages/05/bf/1cad7f0e8d03f5f5b2b417cda8859e4d968d2eebdca0cd336b23d7dbbdbb/fastokens-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:01b9bdba818d7b2c67d57d9917faf7a1dad32ece0734440130de94ad768b819f", size = 3336689, upload-time = "2026-05-17T10:32:46.21Z" }, + { url = "https://files.pythonhosted.org/packages/05/56/0030c6e67c60ee88b74336d1bb03eb556b2afa60445268921ad02d9cb3b3/fastokens-0.2.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:9aec70b85a06bf2ac95dd76e07e404040dbcfb06eb165f29bc61ef2ab68dc87a", size = 3154666, upload-time = "2026-05-17T10:32:48.835Z" }, + { url = "https://files.pythonhosted.org/packages/c1/5b/02cc5d501ccc2fbd4b068a7aa34a35347bdb3a4189b96af647ef0407af87/fastokens-0.2.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:8c41f5278ac53853249c1170d653ee0afaa0906c9bc32c8d25c9443b6d667298", size = 3406657, upload-time = "2026-05-17T10:32:51.392Z" }, + { url = "https://files.pythonhosted.org/packages/97/d7/f5fb2564e16b1f5733e05c41b090f95a3fe767f6b888ba7d864193bc5447/fastokens-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d068bc50082ad67d5d542847075f1f7b8d10f703274e56e241312f18b4d9e772", size = 3598064, upload-time = "2026-05-17T10:32:54.109Z" }, + { url = "https://files.pythonhosted.org/packages/0a/39/2098de2aa01c3e2ef62b066926d70015f88845e3ac1a976ba1cc3a363c05/fastokens-0.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:5729c44ce1d60cb03e506731dcb17d8c2d69c267098c3ff35ca8be37d618714d", size = 2767905, upload-time = "2026-05-17T10:32:56.759Z" }, ] [[package]] @@ -654,22 +525,6 @@ version = "1.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, @@ -734,38 +589,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, - { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, - { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, - { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, - { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, - { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, - { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, - { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, - { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, - { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, - { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, - { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, - { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, - { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, - { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, - { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, - { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, - { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, - { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, - { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, - { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, - { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, - { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, - { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] @@ -947,18 +770,6 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9d/c0/a3bb4cc13aced219dd18191ea66e874266bd8aa7b96744e495e1c733aa2d/jiter-0.11.0.tar.gz", hash = "sha256:1d9637eaf8c1d6a63d6562f2a6e5ab3af946c66037eb1b894e8fad75422266e4", size = 167094, upload-time = "2025-09-15T09:20:38.212Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/21/7dd1235a19e26979be6098e87e4cced2e061752f3a40a17bbce6dea7fae1/jiter-0.11.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3893ce831e1c0094a83eeaf56c635a167d6fa8cc14393cc14298fd6fdc2a2449", size = 309875, upload-time = "2025-09-15T09:18:48.41Z" }, - { url = "https://files.pythonhosted.org/packages/71/f9/462b54708aa85b135733ccba70529dd68a18511bf367a87c5fd28676c841/jiter-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:25c625b9b61b5a8725267fdf867ef2e51b429687f6a4eef211f4612e95607179", size = 316505, upload-time = "2025-09-15T09:18:51.057Z" }, - { url = "https://files.pythonhosted.org/packages/bd/40/14e2eeaac6a47bff27d213834795472355fd39769272eb53cb7aa83d5aa8/jiter-0.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd4ca85fb6a62cf72e1c7f5e34ddef1b660ce4ed0886ec94a1ef9777d35eaa1f", size = 337613, upload-time = "2025-09-15T09:18:52.358Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ed/a5f1f8419c92b150a7c7fb5ccba1fb1e192887ad713d780e70874f0ce996/jiter-0.11.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:572208127034725e79c28437b82414028c3562335f2b4f451d98136d0fc5f9cd", size = 361438, upload-time = "2025-09-15T09:18:54.637Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f5/70682c023dfcdd463a53faf5d30205a7d99c51d70d3e303c932d0936e5a2/jiter-0.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:494ba627c7f550ad3dabb21862864b8f2216098dc18ff62f37b37796f2f7c325", size = 486180, upload-time = "2025-09-15T09:18:56.158Z" }, - { url = "https://files.pythonhosted.org/packages/7c/39/020d08cbab4eab48142ad88b837c41eb08a15c0767fdb7c0d3265128a44b/jiter-0.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8da18a99f58bca3ecc2d2bba99cac000a924e115b6c4f0a2b98f752b6fbf39a", size = 376681, upload-time = "2025-09-15T09:18:57.553Z" }, - { url = "https://files.pythonhosted.org/packages/52/10/b86733f6e594cf51dd142f37c602d8df87c554c5844958deaab0de30eb5d/jiter-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ffd3b0fff3fabbb02cc09910c08144db6bb5697a98d227a074401e01ee63dd", size = 348685, upload-time = "2025-09-15T09:18:59.208Z" }, - { url = "https://files.pythonhosted.org/packages/fb/ee/8861665e83a9e703aa5f65fddddb6225428e163e6b0baa95a7f9a8fb9aae/jiter-0.11.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fe6530aa738a4f7d4e4702aa8f9581425d04036a5f9e25af65ebe1f708f23be", size = 385573, upload-time = "2025-09-15T09:19:00.593Z" }, - { url = "https://files.pythonhosted.org/packages/25/74/05afec03600951f128293813b5a208c9ba1bf587c57a344c05a42a69e1b1/jiter-0.11.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e35d66681c133a03d7e974e7eedae89720fe8ca3bd09f01a4909b86a8adf31f5", size = 516669, upload-time = "2025-09-15T09:19:02.369Z" }, - { url = "https://files.pythonhosted.org/packages/93/d1/2e5bfe147cfbc2a5eef7f73eb75dc5c6669da4fa10fc7937181d93af9495/jiter-0.11.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59459beca2fbc9718b6f1acb7bfb59ebc3eb4294fa4d40e9cb679dafdcc6c60", size = 508767, upload-time = "2025-09-15T09:19:04.011Z" }, - { url = "https://files.pythonhosted.org/packages/87/50/597f71307e10426b5c082fd05d38c615ddbdd08c3348d8502963307f0652/jiter-0.11.0-cp310-cp310-win32.whl", hash = "sha256:b7b0178417b0dcfc5f259edbc6db2b1f5896093ed9035ee7bab0f2be8854726d", size = 205476, upload-time = "2025-09-15T09:19:05.594Z" }, - { url = "https://files.pythonhosted.org/packages/c7/86/1e5214b3272e311754da26e63edec93a183811d4fc2e0118addec365df8b/jiter-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:11df2bf99fb4754abddd7f5d940a48e51f9d11624d6313ca4314145fcad347f0", size = 204708, upload-time = "2025-09-15T09:19:06.955Z" }, { url = "https://files.pythonhosted.org/packages/38/55/a69fefeef09c2eaabae44b935a1aa81517e49639c0a0c25d861cb18cd7ac/jiter-0.11.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cb5d9db02979c3f49071fce51a48f4b4e4cf574175fb2b11c7a535fa4867b222", size = 309503, upload-time = "2025-09-15T09:19:08.191Z" }, { url = "https://files.pythonhosted.org/packages/bd/d5/a6aba9e6551f32f9c127184f398208e4eddb96c59ac065c8a92056089d28/jiter-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1dc6a123f3471c4730db7ca8ba75f1bb3dcb6faeb8d46dd781083e7dee88b32d", size = 317688, upload-time = "2025-09-15T09:19:09.918Z" }, { url = "https://files.pythonhosted.org/packages/bb/f3/5e86f57c1883971cdc8535d0429c2787bf734840a231da30a3be12850562/jiter-0.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09858f8d230f031c7b8e557429102bf050eea29c77ad9c34c8fe253c5329acb7", size = 337418, upload-time = "2025-09-15T09:19:11.078Z" }, @@ -998,19 +809,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/13/3a/d61707803260d59520721fa326babfae25e9573a88d8b7b9cb54c5423a59/jiter-0.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:089f9df9f69532d1339e83142438668f52c97cd22ee2d1195551c2b1a9e6cf33", size = 313737, upload-time = "2025-09-15T09:19:59.638Z" }, { url = "https://files.pythonhosted.org/packages/cd/cc/c9f0eec5d00f2a1da89f6bdfac12b8afdf8d5ad974184863c75060026457/jiter-0.11.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29ed1fe69a8c69bf0f2a962d8d706c7b89b50f1332cd6b9fbda014f60bd03a03", size = 346183, upload-time = "2025-09-15T09:20:01.442Z" }, { url = "https://files.pythonhosted.org/packages/a6/87/fc632776344e7aabbab05a95a0075476f418c5d29ab0f2eec672b7a1f0ac/jiter-0.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a4d71d7ea6ea8786291423fe209acf6f8d398a0759d03e7f24094acb8ab686ba", size = 204225, upload-time = "2025-09-15T09:20:03.102Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3b/e7f45be7d3969bdf2e3cd4b816a7a1d272507cd0edd2d6dc4b07514f2d9a/jiter-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9a6dff27eca70930bdbe4cbb7c1a4ba8526e13b63dc808c0670083d2d51a4a72", size = 304414, upload-time = "2025-09-15T09:20:04.357Z" }, - { url = "https://files.pythonhosted.org/packages/06/32/13e8e0d152631fcc1907ceb4943711471be70496d14888ec6e92034e2caf/jiter-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ae2a7593a62132c7d4c2abbee80bbbb94fdc6d157e2c6cc966250c564ef774", size = 314223, upload-time = "2025-09-15T09:20:05.631Z" }, - { url = "https://files.pythonhosted.org/packages/0c/7e/abedd5b5a20ca083f778d96bba0d2366567fcecb0e6e34ff42640d5d7a18/jiter-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b13a431dba4b059e9e43019d3022346d009baf5066c24dcdea321a303cde9f0", size = 337306, upload-time = "2025-09-15T09:20:06.917Z" }, - { url = "https://files.pythonhosted.org/packages/ac/e2/30d59bdc1204c86aa975ec72c48c482fee6633120ee9c3ab755e4dfefea8/jiter-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af62e84ca3889604ebb645df3b0a3f3bcf6b92babbff642bd214616f57abb93a", size = 360565, upload-time = "2025-09-15T09:20:08.283Z" }, - { url = "https://files.pythonhosted.org/packages/fe/88/567288e0d2ed9fa8f7a3b425fdaf2cb82b998633c24fe0d98f5417321aa8/jiter-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f3b32bb723246e6b351aecace52aba78adb8eeb4b2391630322dc30ff6c773", size = 486465, upload-time = "2025-09-15T09:20:09.613Z" }, - { url = "https://files.pythonhosted.org/packages/18/6e/7b72d09273214cadd15970e91dd5ed9634bee605176107db21e1e4205eb1/jiter-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:adcab442f4a099a358a7f562eaa54ed6456fb866e922c6545a717be51dbed7d7", size = 377581, upload-time = "2025-09-15T09:20:10.884Z" }, - { url = "https://files.pythonhosted.org/packages/58/52/4db456319f9d14deed325f70102577492e9d7e87cf7097bda9769a1fcacb/jiter-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9967c2ab338ee2b2c0102fd379ec2693c496abf71ffd47e4d791d1f593b68e2", size = 347102, upload-time = "2025-09-15T09:20:12.175Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b4/433d5703c38b26083aec7a733eb5be96f9c6085d0e270a87ca6482cbf049/jiter-0.11.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e7d0bed3b187af8b47a981d9742ddfc1d9b252a7235471ad6078e7e4e5fe75c2", size = 386477, upload-time = "2025-09-15T09:20:13.428Z" }, - { url = "https://files.pythonhosted.org/packages/c8/7a/a60bfd9c55b55b07c5c441c5085f06420b6d493ce9db28d069cc5b45d9f3/jiter-0.11.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:f6fe0283e903ebc55f1a6cc569b8c1f3bf4abd026fed85e3ff8598a9e6f982f0", size = 516004, upload-time = "2025-09-15T09:20:14.848Z" }, - { url = "https://files.pythonhosted.org/packages/2e/46/f8363e5ecc179b4ed0ca6cb0a6d3bfc266078578c71ff30642ea2ce2f203/jiter-0.11.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5821e3d66606b29ae5b497230b304f1376f38137d69e35f8d2bd5f310ff73", size = 507855, upload-time = "2025-09-15T09:20:16.176Z" }, - { url = "https://files.pythonhosted.org/packages/90/33/396083357d51d7ff0f9805852c288af47480d30dd31d8abc74909b020761/jiter-0.11.0-cp314-cp314-win32.whl", hash = "sha256:c2d13ba7567ca8799f17c76ed56b1d49be30df996eb7fa33e46b62800562a5e2", size = 205802, upload-time = "2025-09-15T09:20:17.661Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ab/eb06ca556b2551d41de7d03bf2ee24285fa3d0c58c5f8d95c64c9c3281b1/jiter-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb4790497369d134a07fc763cc88888c46f734abdd66f9fdf7865038bf3a8f40", size = 313405, upload-time = "2025-09-15T09:20:18.918Z" }, - { url = "https://files.pythonhosted.org/packages/af/22/7ab7b4ec3a1c1f03aef376af11d23b05abcca3fb31fbca1e7557053b1ba2/jiter-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e2bbf24f16ba5ad4441a9845e40e4ea0cb9eed00e76ba94050664ef53ef4406", size = 347102, upload-time = "2025-09-15T09:20:20.16Z" }, { url = "https://files.pythonhosted.org/packages/70/f3/ce100253c80063a7b8b406e1d1562657fd4b9b4e1b562db40e68645342fb/jiter-0.11.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:902b43386c04739229076bd1c4c69de5d115553d982ab442a8ae82947c72ede7", size = 336380, upload-time = "2025-09-15T09:20:36.867Z" }, ] @@ -1066,6 +864,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820, upload-time = "2024-02-04T14:48:02.496Z" }, ] +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + [[package]] name = "markdown-it-py" version = "4.0.0" @@ -1092,17 +903,6 @@ version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, @@ -1147,28 +947,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] [[package]] @@ -1244,14 +1022,6 @@ version = "1.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/a2/3b68a9e769db68668b25c6108444a35f9bd163bb848c0650d516761a59c0/msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", size = 81318, upload-time = "2025-10-08T09:14:38.722Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e1/2b720cc341325c00be44e1ed59e7cfeae2678329fbf5aa68f5bda57fe728/msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", size = 83786, upload-time = "2025-10-08T09:14:40.082Z" }, - { url = "https://files.pythonhosted.org/packages/71/e5/c2241de64bfceac456b140737812a2ab310b10538a7b34a1d393b748e095/msgpack-1.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", size = 398240, upload-time = "2025-10-08T09:14:41.151Z" }, - { url = "https://files.pythonhosted.org/packages/b7/09/2a06956383c0fdebaef5aa9246e2356776f12ea6f2a44bd1368abf0e46c4/msgpack-1.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", size = 406070, upload-time = "2025-10-08T09:14:42.821Z" }, - { url = "https://files.pythonhosted.org/packages/0e/74/2957703f0e1ef20637d6aead4fbb314330c26f39aa046b348c7edcf6ca6b/msgpack-1.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", size = 393403, upload-time = "2025-10-08T09:14:44.38Z" }, - { url = "https://files.pythonhosted.org/packages/a5/09/3bfc12aa90f77b37322fc33e7a8a7c29ba7c8edeadfa27664451801b9860/msgpack-1.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", size = 398947, upload-time = "2025-10-08T09:14:45.56Z" }, - { url = "https://files.pythonhosted.org/packages/4b/4f/05fcebd3b4977cb3d840f7ef6b77c51f8582086de5e642f3fefee35c86fc/msgpack-1.1.2-cp310-cp310-win32.whl", hash = "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", size = 64769, upload-time = "2025-10-08T09:14:47.334Z" }, - { url = "https://files.pythonhosted.org/packages/d0/3e/b4547e3a34210956382eed1c85935fff7e0f9b98be3106b3745d7dec9c5e/msgpack-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", size = 71293, upload-time = "2025-10-08T09:14:48.665Z" }, { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, @@ -1279,53 +1049,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, - { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, - { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, - { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, - { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, - { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, - { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, - { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, - { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, - { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, ] [[package]] name = "multidict" version = "6.7.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, @@ -1398,42 +1129,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, - { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, - { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, - { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, - { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, - { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, - { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, - { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, - { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, - { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, - { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, - { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, - { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, - { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, - { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, - { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, - { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, - { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, - { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, - { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, - { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, - { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, - { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, - { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, - { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] @@ -1446,8 +1141,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/04f39c5d0d0def03247c2893d6f2b83c136bf3320a2154d7b8858f2ba72d/multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", size = 1772603, upload-time = "2024-01-28T18:52:34.85Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/76/6e712a2623d146d314f17598df5de7224c85c0060ef63fd95cc15a25b3fa/multiprocess-0.70.16-pp310-pypy310_pp73-macosx_10_13_x86_64.whl", hash = "sha256:476887be10e2f59ff183c006af746cb6f1fd0eadcfd4ef49e605cbe2659920ee", size = 134980, upload-time = "2024-01-28T18:52:15.731Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ab/1e6e8009e380e22254ff539ebe117861e5bdb3bff1fc977920972237c6c7/multiprocess-0.70.16-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d951bed82c8f73929ac82c61f01a7b5ce8f3e5ef40f5b52553b4f547ce2b08ec", size = 134982, upload-time = "2024-01-28T18:52:17.783Z" }, { url = "https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", size = 134824, upload-time = "2024-01-28T18:52:26.062Z" }, { url = "https://files.pythonhosted.org/packages/50/15/b56e50e8debaf439f44befec5b2af11db85f6e0f344c3113ae0be0593a91/multiprocess-0.70.16-py311-none-any.whl", hash = "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a", size = 143519, upload-time = "2024-01-28T18:52:28.115Z" }, { url = "https://files.pythonhosted.org/packages/0a/7d/a988f258104dcd2ccf1ed40fdc97e26c4ac351eeaf81d76e266c52d84e2f/multiprocess-0.70.16-py312-none-any.whl", hash = "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e", size = 146741, upload-time = "2024-01-28T18:52:29.395Z" }, @@ -1455,15 +1148,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351, upload-time = "2024-01-28T18:52:31.981Z" }, ] -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -1473,79 +1157,10 @@ 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 = "numpy" -version = "2.2.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, -] - [[package]] name = "numpy" version = "2.3.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/45/e80d203ef6b267aa29b22714fb558930b27960a0c5ce3c19c999232bb3eb/numpy-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ffc4f5caba7dfcbe944ed674b7eef683c7e94874046454bb79ed7ee0236f59d", size = 21259253, upload-time = "2025-09-09T15:56:02.094Z" }, @@ -1592,28 +1207,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" }, { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" }, { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" }, - { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" }, - { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" }, - { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" }, - { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" }, - { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" }, - { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" }, - { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" }, - { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" }, - { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" }, - { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" }, - { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" }, - { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" }, - { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" }, - { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" }, - { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" }, - { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" }, - { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" }, { url = "https://files.pythonhosted.org/packages/b8/f2/7e0a37cfced2644c9563c529f29fa28acbd0960dde32ece683aafa6f4949/numpy-2.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1e02c7159791cd481e1e6d5ddd766b62a4d5acf8df4d4d1afe35ee9c5c33a41e", size = 21131019, upload-time = "2025-09-09T15:58:42.838Z" }, { url = "https://files.pythonhosted.org/packages/1a/7e/3291f505297ed63831135a6cc0f474da0c868a1f31b0dd9a9f03a7a0d2ed/numpy-2.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:dca2d0fc80b3893ae72197b39f69d55a3cd8b17ea1b50aa4c62de82419936150", size = 14376288, upload-time = "2025-09-09T15:58:45.425Z" }, { url = "https://files.pythonhosted.org/packages/bf/4b/ae02e985bdeee73d7b5abdefeb98aef1207e96d4c0621ee0cf228ddfac3c/numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:99683cbe0658f8271b333a1b1b4bb3173750ad59c0c61f5bbdc5b318918fffe3", size = 5305425, upload-time = "2025-09-09T15:58:48.6Z" }, @@ -1660,6 +1253,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/65/59/fd49fd2c3184c0d5fedb8c9c456ae9852154828bca7ee69dce004ea83188/openai_agents-0.3.3-py3-none-any.whl", hash = "sha256:aa2c74e010b923c09f166e63a51fae8c850c62df8581b84bafcbe5bd208d1505", size = 210893, upload-time = "2025-09-30T23:20:22.037Z" }, ] +[[package]] +name = "openai-harmony" +version = "0.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/92/2d038d096f29179c7c9571b431f9e739f87a487121901725e23fe338dd9d/openai_harmony-0.0.8.tar.gz", hash = "sha256:6e43f98e6c242fa2de6f8ea12eab24af63fa2ed3e89c06341fb9d92632c5cbdf", size = 284777, upload-time = "2025-11-05T19:07:06.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/c6/2502f416d46be3ec08bb66d696cccffb57781a499e3ff2e4d7c174af4e8f/openai_harmony-0.0.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:029ec25ca74abe48fdb58eb9fdd2a8c1618581fc33ce8e5653f8a1ffbfbd9326", size = 2627806, upload-time = "2025-11-05T19:06:57.063Z" }, + { url = "https://files.pythonhosted.org/packages/d3/d2/ce6953ca87db9cae3e775024184da7d1c5cb88cead19a2d75b42f00a959c/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4f709815924ec325b9a890e6ab2bbb0ceec8e319a4e257328eb752cf36b2efc", size = 2948463, upload-time = "2025-11-05T19:06:48.17Z" }, + { url = "https://files.pythonhosted.org/packages/fa/4c/b553c9651662d6ce102ca7f3629d268b23df1abe5841e24bed81e8a8e949/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cfcfd963b50a41fc656c84d3440ca6eecdccd6c552158ce790b8f2e33dfb5a9", size = 2704083, upload-time = "2025-11-05T19:06:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/9b/af/4eec8f9ab9c27bcdb444460c72cf43011d176fc44c79d6e113094ca1e152/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a3a16972aa1cee38ea958470cd04ac9a2d5ac38fdcf77ab686611246220c158", size = 2959765, upload-time = "2025-11-05T19:06:53.62Z" }, + { url = "https://files.pythonhosted.org/packages/11/3c/33f3374e4624e0e776f6b13b73c45a7ead7f9c4529f8369ed5bfcaa30cac/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4d5cfa168e74d08f8ba6d58a7e49bc7daef4d58951ec69b66b0d56f4927a68d", size = 3427031, upload-time = "2025-11-05T19:06:51.829Z" }, + { url = "https://files.pythonhosted.org/packages/25/3f/1a192b93bb47c6b44cd98ba8cc1d3d2a9308f1bb700c3017e6352da11bda/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c007d277218a50db8839e599ed78e0fffe5130f614c3f6d93ae257f282071a29", size = 2953260, upload-time = "2025-11-05T19:06:55.406Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/93b582cad3531797c3db7c2db5400fd841538ccddfd9f5e3df61be99a630/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8565d4f5a0638da1bffde29832ed63c9e695c558611053add3b2dc0b56c92dbc", size = 3127044, upload-time = "2025-11-05T19:06:59.553Z" }, + { url = "https://files.pythonhosted.org/packages/1d/10/4327dbf87f75ae813405fd9a9b4a5cde63d506ffed0a096a440a4cabd89c/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:cbaa3bda75ef0d8836e1f8cc84af62f971b1d756d740efc95c38c3e04c0bfde2", size = 2932931, upload-time = "2025-11-05T19:07:01.437Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c8/1774eec4f6f360ef57618fb8f52e3d3af245b2491bd0297513aa09eec04b/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:772922a9bd24e133950fad71eb1550836f415a88e8c77870e12d0c3bd688ddc2", size = 2996140, upload-time = "2025-11-05T19:07:03.438Z" }, + { url = "https://files.pythonhosted.org/packages/60/c3/3d1e01e2dba517a91760e4a03e4f20ffc75039a6fe584d0e6f9b5c78fd15/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:007b0476a1f331f8130783f901f1da6f5a7057af1a4891f1b6a31dec364189b5", size = 3205080, upload-time = "2025-11-05T19:07:05.078Z" }, + { url = "https://files.pythonhosted.org/packages/14/63/119de431572d7c70a7bf1037034a9be6ed0a7502a7498ba7302bca5b3242/openai_harmony-0.0.8-cp38-abi3-win32.whl", hash = "sha256:a9b5f893326b28d9e935ade14b4f655f5a840942473bc89b201c25f7a15af9cf", size = 2082457, upload-time = "2025-11-05T19:07:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/c83cf5a206c263ee70448a5ae4264682555f4d0b5bed0d2cc6ca1108103d/openai_harmony-0.0.8-cp38-abi3-win_amd64.whl", hash = "sha256:39d44f0d8f466bd56698e7ead708bead3141e27b9b87e3ab7d5a6d0e4a869ee5", size = 2438369, upload-time = "2025-11-05T19:07:08.1Z" }, +] + [[package]] name = "opentelemetry-api" version = "1.39.1" @@ -1687,21 +1303,13 @@ name = "pandas" version = "2.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, @@ -1729,19 +1337,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, ] [[package]] @@ -1829,7 +1424,7 @@ requires-dist = [ { name = "ty", marker = "extra == 'dev'", specifier = ">=0.0.0a6" }, { name = "typer", specifier = ">=0.9.0,<0.26" }, { name = "types-toml", marker = "extra == 'dev'", specifier = ">=0.10.0" }, - { name = "verifiers", git = "https://github.com/PrimeIntellect-ai/verifiers.git?tag=v0.1.14" }, + { name = "verifiers", specifier = ">=0.1.15.dev371" }, ] provides-extras = ["dev"] @@ -1858,6 +1453,23 @@ requires-dist = [ ] provides-extras = ["dev"] +[[package]] +name = "prime-pydantic-config" +version = "0.3.0.dev86" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/34/006fc720a8fcda84706793582d50a2028bf6950fb7a0eedb59d3f6555261/prime_pydantic_config-0.3.0.dev86.tar.gz", hash = "sha256:1139bb6d21a8cf134e212ee4e529e5150f2db7422b42eae3ca69a5c77b8a69f5", size = 75656, upload-time = "2026-06-02T01:08:19.079Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/a3/ded48c436cd56ddac3b216458ac458eaf069b55e0ca3be506b2508d16fa2/prime_pydantic_config-0.3.0.dev86-py3-none-any.whl", hash = "sha256:51ac33ae1b5de9ba2e44eb9a91242d9dd783784234942f166f6e8974bcdf1577", size = 27437, upload-time = "2026-06-02T01:08:20.23Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli" }, +] + [[package]] name = "prime-sandboxes" source = { editable = "packages/prime-sandboxes" } @@ -1920,21 +1532,6 @@ version = "0.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, @@ -1995,36 +1592,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, - { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, - { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, - { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, - { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, - { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, - { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, - { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, - { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, - { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, - { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, - { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, - { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, - { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, - { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, - { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, - { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, - { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, - { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, - { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, - { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, - { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] @@ -2049,13 +1616,6 @@ version = "24.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/91/13/13e1069b351bdc3881266e11147ffccf687505dbb0ea74036237f5d454a5/pyarrow-24.0.0.tar.gz", hash = "sha256:85fe721a14dd823aca09127acbb06c3ca723efbd436c004f16bca601b04dcc83", size = 1180261, upload-time = "2026-04-21T10:51:25.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/bf/a34fee1d624152124fa8355c42f34195ad5fe5233ce5bb87946432047d52/pyarrow-24.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:7c2b98645d576a0b9616892ead22b64a83a5f043c5e2ca15ebcefcb5b70c80cb", size = 35076681, upload-time = "2026-04-21T08:51:46.845Z" }, - { url = "https://files.pythonhosted.org/packages/1d/41/64180033d7027afce12dc96d0fe1f504c6fa112190582b458acea2399530/pyarrow-24.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:644a246325b8c69c595ad1dd4b463eba4b0cdb731370e4a86137d433208d6147", size = 36684260, upload-time = "2026-04-21T08:51:53.642Z" }, - { url = "https://files.pythonhosted.org/packages/57/02/9b9320e673dd8a99411fac78690f3df92f6dd6f59754c750110bca66d64e/pyarrow-24.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3a577bd840ca83f646f0a625dbc571dba7044c43c2d1503afc378b570954345c", size = 45698566, upload-time = "2026-04-21T10:46:02.133Z" }, - { url = "https://files.pythonhosted.org/packages/67/33/f75e91b9a64c3f33c787e263c93b871ad91b8a4a68c1d5cebddd9840e835/pyarrow-24.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e3268e43984d0b1a185c89b4cfff282a7ead12fc93f56cfd7088bdbcbe727041", size = 48835562, upload-time = "2026-04-21T10:46:10.278Z" }, - { url = "https://files.pythonhosted.org/packages/a5/63/097510448e47e4091faa41c43ba92f97cecaab8f4535b56a3d149578f634/pyarrow-24.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2392d954fcb920f42d230284b677605e4e2fbb11f2821e823e642abd67fbb491", size = 49394997, upload-time = "2026-04-21T10:46:18.08Z" }, - { url = "https://files.pythonhosted.org/packages/60/6b/c047d6222ab279024a062742d1807e2fbaf27bba88a98637299ff47b9236/pyarrow-24.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bec9373df11544592b0ba7ec2af0e35059e5f0e7647c6183a854dedd193298f1", size = 51911424, upload-time = "2026-04-21T10:46:25.347Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ba/464cc70761c2a525d97ebd84e21c31ebd47f3ef4bdcee117009f51c46f24/pyarrow-24.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:c42ab9439498270139cc63e18847a02afe5c8b3ed9c931266533cfe378bd3591", size = 27251730, upload-time = "2026-04-21T10:46:30.913Z" }, { url = "https://files.pythonhosted.org/packages/62/c9/a47ab7ece0d86cbe6678418a0fbd1ac4bb493b9184a3891dfa0e7f287ae0/pyarrow-24.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b0e131f880cda8d04e076cee175a46fc0e8bc8b65c99c6c09dff6669335fde74", size = 35068898, upload-time = "2026-04-21T10:46:36.599Z" }, { url = "https://files.pythonhosted.org/packages/d1/bc/8db86617a9a58008acf8913d6fed68ea2a46acb6de928db28d724c891a68/pyarrow-24.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:1b2fe7f9a5566401a0ef2571f197eb92358925c1f0c8dba305d6e43ea0871bb3", size = 36679915, upload-time = "2026-04-21T10:46:42.602Z" }, { url = "https://files.pythonhosted.org/packages/eb/8e/fb178720400ef69db251eb4a9c3ccf4af269bc1feb5055529b8fc87170d1/pyarrow-24.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:0b3537c00fb8d384f15ac1e79b6eb6db04a16514c8c1d22e59a9b95c8ba42868", size = 45697931, upload-time = "2026-04-21T10:46:48.403Z" }, @@ -2084,20 +1644,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/eb/771f9ecb0c65e73fe9dccdd1717901b9594f08c4515d000c7c62df573811/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:641f795b361874ac9da5294f8f443dfdbee355cf2bd9e3b8d97aaac2306b9b37", size = 49451819, upload-time = "2026-04-21T10:49:21.474Z" }, { url = "https://files.pythonhosted.org/packages/48/da/61ae89a88732f5a785646f3ec6125dbb640fa98a540eb2b9889caa561403/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8adc8e6ce5fccf5dc707046ae4914fd537def529709cc0d285d37a7f9cd442ca", size = 51909252, upload-time = "2026-04-21T10:49:31.164Z" }, { url = "https://files.pythonhosted.org/packages/cb/1a/8dd5cafab7b66573fa91c03d06d213356ad4edd71813aa75e08ce2b3a844/pyarrow-24.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:9b18371ad2f44044b81a8d23bc2d8a9b6a6226dca775e8e16cfee640473d6c5d", size = 27388127, upload-time = "2026-04-21T10:49:37.334Z" }, - { url = "https://files.pythonhosted.org/packages/ad/80/d022a34ff05d2cbedd8ccf841fc1f532ecfa9eb5ed1711b56d0e0ea71fc9/pyarrow-24.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:1cc9057f0319e26333b357e17f3c2c022f1a83739b48a88b25bfd5fa2dc18838", size = 35007997, upload-time = "2026-04-21T10:49:48.796Z" }, - { url = "https://files.pythonhosted.org/packages/1a/ff/f01485fda6f4e5d441afb8dd5e7681e4db18826c1e271852f5d3957d6a80/pyarrow-24.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e6f1278ee4785b6db21229374a1c9e54ec7c549de5d1efc9630b6207de7e170b", size = 36678720, upload-time = "2026-04-21T10:49:55.858Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c2/2d2d5fea814237923f71b36495211f20b43a1576f9a4d6da7e751a64ec6f/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:adbbedc55506cbdabb830890444fb856bfb0060c46c6f8026c6c2f2cf86ae795", size = 45741852, upload-time = "2026-04-21T10:50:04.624Z" }, - { url = "https://files.pythonhosted.org/packages/8e/3a/28ba9c1c1ebdbb5f1b94dfebb46f207e52e6a554b7fe4132540fde29a3a0/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ae8a1145af31d903fa9bb166824d7abe9b4681a000b0159c9fb99c11bc11ad26", size = 48889852, upload-time = "2026-04-21T10:50:12.293Z" }, - { url = "https://files.pythonhosted.org/packages/df/51/4a389acfd31dca009f8fb82d7f510bb4130f2b3a8e18cf00194d0687d8ac/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d7027eba1df3b2069e2e8d80f644fa0918b68c46432af3d088ddd390d063ecde", size = 49445207, upload-time = "2026-04-21T10:50:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/19/4b/0bab2b23d2ae901b1b9a03c0efd4b2d070256f8ce3fc43f6e58c167b2081/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e56a1ffe9bf7b727432b89104cc0849c21582949dd7bdcb34f17b2001a351a76", size = 51954117, upload-time = "2026-04-21T10:50:29.14Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/f4e9145da0417b3d2c12035a8492b35ff4a3dbc653e614fcfb51d9dedb38/pyarrow-24.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:38be1808cdd068605b787e6ca9119b27eb275a0234e50212c3492331680c3b1e", size = 28001155, upload-time = "2026-04-21T10:51:22.337Z" }, - { url = "https://files.pythonhosted.org/packages/79/4f/46a49a63f43526da895b1a45bbb51d5baf8e4d77159f8528fc3e5490007f/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:418e48ce50a45a6a6c73c454677203a9c75c966cb1e92ca3370959185f197a05", size = 35250387, upload-time = "2026-04-21T10:50:35.552Z" }, - { url = "https://files.pythonhosted.org/packages/a0/da/d5e0cd5ef00796922404806d5f00325cdadc3441ce2c13fe7115f2df9a64/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:2f16197705a230a78270cdd4ea8a1d57e86b2fdcbc34a1f6aebc72e65c986f9a", size = 36797102, upload-time = "2026-04-21T10:50:42.417Z" }, - { url = "https://files.pythonhosted.org/packages/34/c7/5904145b0a593a05236c882933d439b5720f0a145381179063722fbfc123/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:fb24ac194bfc5e86839d7dcd52092ee31e5fe6733fe11f5e3b06ef0812b20072", size = 45745118, upload-time = "2026-04-21T10:50:49.324Z" }, - { url = "https://files.pythonhosted.org/packages/13/d3/cca42fe166d1c6e4d5b80e530b7949104d10e17508a90ae202dac205ce2a/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:9700ebd9a51f5895ce75ff4ac4b3c47a7d4b42bc618be8e713e5d56bacf5f931", size = 48844765, upload-time = "2026-04-21T10:50:55.579Z" }, - { url = "https://files.pythonhosted.org/packages/b0/49/942c3b79878ba928324d1e17c274ed84581db8c0a749b24bcf4cbdf15bd3/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d8ddd2768da81d3ee08cfea9b597f4abb4e8e1dc8ae7e204b608d23a0d3ab699", size = 49471890, upload-time = "2026-04-21T10:51:02.439Z" }, - { url = "https://files.pythonhosted.org/packages/76/97/ff71431000a75d84135a1ace5ca4ba11726a231a8007bbb320a4c54075d5/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:61a3d7eaa97a14768b542f3d284dc6400dd2470d9f080708b13cd46b6ae18136", size = 51932250, upload-time = "2026-04-21T10:51:10.576Z" }, - { url = "https://files.pythonhosted.org/packages/51/be/6f79d55816d5c22557cf27533543d5d70dfe692adfbee4b99f2760674f38/pyarrow-24.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:c91d00057f23b8d353039520dc3a6c09d8608164c692e9f59a175a42b2ae0c19", size = 28131282, upload-time = "2026-04-21T10:51:16.815Z" }, ] [[package]] @@ -2133,19 +1679,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/7d/14/12b4a0d2b0b10d8e1d9a24ad94e7bbb43335eaf29c0c4e57860e8a30734a/pydantic_core-2.41.1.tar.gz", hash = "sha256:1ad375859a6d8c356b7704ec0f547a58e82ee80bb41baa811ad710e124bc8f2f", size = 454870, upload-time = "2025-10-07T10:50:45.974Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2c/a5c4640dc7132540109f67fe83b566fbc7512ccf2a068cfa22a243df70c7/pydantic_core-2.41.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e63036298322e9aea1c8b7c0a6c1204d615dbf6ec0668ce5b83ff27f07404a61", size = 2113814, upload-time = "2025-10-06T21:09:50.892Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e7/a8694c3454a57842095d69c7a4ab3cf81c3c7b590f052738eabfdfc2e234/pydantic_core-2.41.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:241299ca91fc77ef64f11ed909d2d9220a01834e8e6f8de61275c4dd16b7c936", size = 1916660, upload-time = "2025-10-06T21:09:52.783Z" }, - { url = "https://files.pythonhosted.org/packages/9c/58/29f12e65b19c1877a0269eb4f23c5d2267eded6120a7d6762501ab843dc9/pydantic_core-2.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab7e594a2a5c24ab8013a7dc8cfe5f2260e80e490685814122081705c2cf2b0", size = 1975071, upload-time = "2025-10-06T21:09:54.009Z" }, - { url = "https://files.pythonhosted.org/packages/98/26/4e677f2b7ec3fbdd10be6b586a82a814c8ebe3e474024c8df2d4260e564e/pydantic_core-2.41.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b054ef1a78519cb934b58e9c90c09e93b837c935dcd907b891f2b265b129eb6e", size = 2067271, upload-time = "2025-10-06T21:09:55.175Z" }, - { url = "https://files.pythonhosted.org/packages/29/50/50614bd906089904d7ca1be3b9ecf08c00a327143d48f1decfdc21b3c302/pydantic_core-2.41.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2ab7d10d0ab2ed6da54c757233eb0f48ebfb4f86e9b88ccecb3f92bbd61a538", size = 2253207, upload-time = "2025-10-06T21:09:56.709Z" }, - { url = "https://files.pythonhosted.org/packages/ea/58/b1e640b4ca559273cca7c28e0fe8891d5d8e9a600f5ab4882670ec107549/pydantic_core-2.41.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2757606b7948bb853a27e4040820306eaa0ccb9e8f9f8a0fa40cb674e170f350", size = 2375052, upload-time = "2025-10-06T21:09:57.97Z" }, - { url = "https://files.pythonhosted.org/packages/53/25/cd47df3bfb24350e03835f0950288d1054f1cc9a8023401dabe6d4ff2834/pydantic_core-2.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec0e75eb61f606bad0a32f2be87507087514e26e8c73db6cbdb8371ccd27917", size = 2076834, upload-time = "2025-10-06T21:09:59.58Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b4/71b2c77e5df527fbbc1a03e72c3fd96c44cd10d4241a81befef8c12b9fc4/pydantic_core-2.41.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0234236514f44a5bf552105cfe2543a12f48203397d9d0f866affa569345a5b5", size = 2195374, upload-time = "2025-10-06T21:10:01.18Z" }, - { url = "https://files.pythonhosted.org/packages/aa/08/4b8a50733005865efde284fec45da75fe16a258f706e16323c5ace4004eb/pydantic_core-2.41.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1b974e41adfbb4ebb0f65fc4ca951347b17463d60893ba7d5f7b9bb087c83897", size = 2156060, upload-time = "2025-10-06T21:10:02.74Z" }, - { url = "https://files.pythonhosted.org/packages/83/c3/1037cb603ef2130c210150a51b1710d86825b5c28df54a55750099f91196/pydantic_core-2.41.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:248dafb3204136113c383e91a4d815269f51562b6659b756cf3df14eefc7d0bb", size = 2331640, upload-time = "2025-10-06T21:10:04.39Z" }, - { url = "https://files.pythonhosted.org/packages/56/4c/52d111869610e6b1a46e1f1035abcdc94d0655587e39104433a290e9f377/pydantic_core-2.41.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:678f9d76a91d6bcedd7568bbf6beb77ae8447f85d1aeebaab7e2f0829cfc3a13", size = 2329844, upload-time = "2025-10-06T21:10:05.68Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/4b435f0b52ab543967761aca66b84ad3f0026e491e57de47693d15d0a8db/pydantic_core-2.41.1-cp310-cp310-win32.whl", hash = "sha256:dff5bee1d21ee58277900692a641925d2dddfde65182c972569b1a276d2ac8fb", size = 1991289, upload-time = "2025-10-06T21:10:07.199Z" }, - { url = "https://files.pythonhosted.org/packages/88/52/31b4deafc1d3cb96d0e7c0af70f0dc05454982d135d07f5117e6336153e8/pydantic_core-2.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:5042da12e5d97d215f91567110fdfa2e2595a25f17c19b9ff024f31c34f9b53e", size = 2027747, upload-time = "2025-10-06T21:10:08.503Z" }, { url = "https://files.pythonhosted.org/packages/f6/a9/ec440f02e57beabdfd804725ef1e38ac1ba00c49854d298447562e119513/pydantic_core-2.41.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4f276a6134fe1fc1daa692642a3eaa2b7b858599c49a7610816388f5e37566a1", size = 2111456, upload-time = "2025-10-06T21:10:09.824Z" }, { url = "https://files.pythonhosted.org/packages/f0/f9/6bc15bacfd8dcfc073a1820a564516d9c12a435a9a332d4cbbfd48828ddd/pydantic_core-2.41.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07588570a805296ece009c59d9a679dc08fab72fb337365afb4f3a14cfbfc176", size = 1915012, upload-time = "2025-10-06T21:10:11.599Z" }, { url = "https://files.pythonhosted.org/packages/38/8a/d9edcdcdfe80bade17bed424284427c08bea892aaec11438fa52eaeaf79c/pydantic_core-2.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28527e4b53400cd60ffbd9812ccb2b5135d042129716d71afd7e45bf42b855c0", size = 1973762, upload-time = "2025-10-06T21:10:13.154Z" }, @@ -2191,23 +1724,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/04/28b040e88c1b89d851278478842f0bdf39c7a05da9e850333c6c8cbe7dfa/pydantic_core-2.41.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:440d0df7415b50084a4ba9d870480c16c5f67c0d1d4d5119e3f70925533a0edc", size = 1875626, upload-time = "2025-10-06T21:11:15.69Z" }, { url = "https://files.pythonhosted.org/packages/d6/58/b41dd3087505220bb58bc81be8c3e8cbc037f5710cd3c838f44f90bdd704/pydantic_core-2.41.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71eaa38d342099405dae6484216dcf1e8e4b0bebd9b44a4e08c9b43db6a2ab67", size = 2045708, upload-time = "2025-10-06T21:11:17.258Z" }, { url = "https://files.pythonhosted.org/packages/d7/b8/760f23754e40bf6c65b94a69b22c394c24058a0ef7e2aa471d2e39219c1a/pydantic_core-2.41.1-cp313-cp313t-win_amd64.whl", hash = "sha256:555ecf7e50f1161d3f693bc49f23c82cf6cdeafc71fa37a06120772a09a38795", size = 1997171, upload-time = "2025-10-06T21:11:18.822Z" }, - { url = "https://files.pythonhosted.org/packages/41/12/cec246429ddfa2778d2d6301eca5362194dc8749ecb19e621f2f65b5090f/pydantic_core-2.41.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:05226894a26f6f27e1deb735d7308f74ef5fa3a6de3e0135bb66cdcaee88f64b", size = 2107836, upload-time = "2025-10-06T21:11:20.432Z" }, - { url = "https://files.pythonhosted.org/packages/20/39/baba47f8d8b87081302498e610aefc37142ce6a1cc98b2ab6b931a162562/pydantic_core-2.41.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:85ff7911c6c3e2fd8d3779c50925f6406d770ea58ea6dde9c230d35b52b16b4a", size = 1904449, upload-time = "2025-10-06T21:11:22.185Z" }, - { url = "https://files.pythonhosted.org/packages/50/32/9a3d87cae2c75a5178334b10358d631bd094b916a00a5993382222dbfd92/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47f1f642a205687d59b52dc1a9a607f45e588f5a2e9eeae05edd80c7a8c47674", size = 1961750, upload-time = "2025-10-06T21:11:24.348Z" }, - { url = "https://files.pythonhosted.org/packages/27/42/a96c9d793a04cf2a9773bff98003bb154087b94f5530a2ce6063ecfec583/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df11c24e138876ace5ec6043e5cae925e34cf38af1a1b3d63589e8f7b5f5cdc4", size = 2063305, upload-time = "2025-10-06T21:11:26.556Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8d/028c4b7d157a005b1f52c086e2d4b0067886b213c86220c1153398dbdf8f/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f0bf7f5c8f7bf345c527e8a0d72d6b26eda99c1227b0c34e7e59e181260de31", size = 2228959, upload-time = "2025-10-06T21:11:28.426Z" }, - { url = "https://files.pythonhosted.org/packages/08/f7/ee64cda8fcc9ca3f4716e6357144f9ee71166775df582a1b6b738bf6da57/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82b887a711d341c2c47352375d73b029418f55b20bd7815446d175a70effa706", size = 2345421, upload-time = "2025-10-06T21:11:30.226Z" }, - { url = "https://files.pythonhosted.org/packages/13/c0/e8ec05f0f5ee7a3656973ad9cd3bc73204af99f6512c1a4562f6fb4b3f7d/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5f1d5d6bbba484bdf220c72d8ecd0be460f4bd4c5e534a541bb2cd57589fb8b", size = 2065288, upload-time = "2025-10-06T21:11:32.019Z" }, - { url = "https://files.pythonhosted.org/packages/0a/25/d77a73ff24e2e4fcea64472f5e39b0402d836da9b08b5361a734d0153023/pydantic_core-2.41.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bf1917385ebe0f968dc5c6ab1375886d56992b93ddfe6bf52bff575d03662be", size = 2189759, upload-time = "2025-10-06T21:11:33.753Z" }, - { url = "https://files.pythonhosted.org/packages/66/45/4a4ebaaae12a740552278d06fe71418c0f2869537a369a89c0e6723b341d/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:4f94f3ab188f44b9a73f7295663f3ecb8f2e2dd03a69c8f2ead50d37785ecb04", size = 2140747, upload-time = "2025-10-06T21:11:35.781Z" }, - { url = "https://files.pythonhosted.org/packages/da/6d/b727ce1022f143194a36593243ff244ed5a1eb3c9122296bf7e716aa37ba/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:3925446673641d37c30bd84a9d597e49f72eacee8b43322c8999fa17d5ae5bc4", size = 2327416, upload-time = "2025-10-06T21:11:37.75Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8c/02df9d8506c427787059f87c6c7253435c6895e12472a652d9616ee0fc95/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:49bd51cc27adb980c7b97357ae036ce9b3c4d0bb406e84fbe16fb2d368b602a8", size = 2318138, upload-time = "2025-10-06T21:11:39.463Z" }, - { url = "https://files.pythonhosted.org/packages/98/67/0cf429a7d6802536941f430e6e3243f6d4b68f41eeea4b242372f1901794/pydantic_core-2.41.1-cp314-cp314-win32.whl", hash = "sha256:a31ca0cd0e4d12ea0df0077df2d487fc3eb9d7f96bbb13c3c5b88dcc21d05159", size = 1998429, upload-time = "2025-10-06T21:11:41.989Z" }, - { url = "https://files.pythonhosted.org/packages/38/60/742fef93de5d085022d2302a6317a2b34dbfe15258e9396a535c8a100ae7/pydantic_core-2.41.1-cp314-cp314-win_amd64.whl", hash = "sha256:1b5c4374a152e10a22175d7790e644fbd8ff58418890e07e2073ff9d4414efae", size = 2028870, upload-time = "2025-10-06T21:11:43.66Z" }, - { url = "https://files.pythonhosted.org/packages/31/38/cdd8ccb8555ef7720bd7715899bd6cfbe3c29198332710e1b61b8f5dd8b8/pydantic_core-2.41.1-cp314-cp314-win_arm64.whl", hash = "sha256:4fee76d757639b493eb600fba668f1e17475af34c17dd61db7a47e824d464ca9", size = 1974275, upload-time = "2025-10-06T21:11:45.476Z" }, - { url = "https://files.pythonhosted.org/packages/e7/7e/8ac10ccb047dc0221aa2530ec3c7c05ab4656d4d4bd984ee85da7f3d5525/pydantic_core-2.41.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f9b9c968cfe5cd576fdd7361f47f27adeb120517e637d1b189eea1c3ece573f4", size = 1875124, upload-time = "2025-10-06T21:11:47.591Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e4/7d9791efeb9c7d97e7268f8d20e0da24d03438a7fa7163ab58f1073ba968/pydantic_core-2.41.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ebc7ab67b856384aba09ed74e3e977dded40e693de18a4f197c67d0d4e6d8e", size = 2043075, upload-time = "2025-10-06T21:11:49.542Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c3/3f6e6b2342ac11ac8cd5cb56e24c7b14afa27c010e82a765ffa5f771884a/pydantic_core-2.41.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8ae0dc57b62a762985bc7fbf636be3412394acc0ddb4ade07fe104230f1b9762", size = 1995341, upload-time = "2025-10-06T21:11:51.497Z" }, { url = "https://files.pythonhosted.org/packages/16/89/d0afad37ba25f5801735af1472e650b86baad9fe807a42076508e4824a2a/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:68f2251559b8efa99041bb63571ec7cdd2d715ba74cc82b3bc9eff824ebc8bf0", size = 2124001, upload-time = "2025-10-07T10:49:54.369Z" }, { url = "https://files.pythonhosted.org/packages/8e/c4/08609134b34520568ddebb084d9ed0a2a3f5f52b45739e6e22cb3a7112eb/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:c7bc140c596097cb53b30546ca257dbe3f19282283190b1b5142928e5d5d3a20", size = 1941841, upload-time = "2025-10-07T10:49:56.248Z" }, { url = "https://files.pythonhosted.org/packages/2a/43/94a4877094e5fe19a3f37e7e817772263e2c573c94f1e3fa2b1eee56ef3b/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2896510fce8f4725ec518f8b9d7f015a00db249d2fd40788f442af303480063d", size = 1961129, upload-time = "2025-10-07T10:49:58.298Z" }, @@ -2216,14 +1732,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5a/bd/389504c9e0600ef4502cd5238396b527afe6ef8981a6a15cd1814fc7b434/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:b3b7d9cfbfdc43c80a16638c6dc2768e3956e73031fca64e8e1a3ae744d1faeb", size = 1927994, upload-time = "2025-10-07T10:50:04.379Z" }, { url = "https://files.pythonhosted.org/packages/ff/9c/5111c6b128861cb792a4c082677e90dac4f2e090bb2e2fe06aa5b2d39027/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec83fc6abef04c7f9bec616e2d76ee9a6a4ae2a359b10c21d0f680e24a247ca", size = 1959394, upload-time = "2025-10-07T10:50:06.335Z" }, { url = "https://files.pythonhosted.org/packages/14/3f/cfec8b9a0c48ce5d64409ec5e1903cb0b7363da38f14b41de2fcb3712700/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6771a2d9f83c4038dfad5970a3eef215940682b2175e32bcc817bdc639019b28", size = 2147365, upload-time = "2025-10-07T10:50:07.978Z" }, - { url = "https://files.pythonhosted.org/packages/d4/31/f403d7ca8352e3e4df352ccacd200f5f7f7fe81cef8e458515f015091625/pydantic_core-2.41.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fabcbdb12de6eada8d6e9a759097adb3c15440fafc675b3e94ae5c9cb8d678a0", size = 2114268, upload-time = "2025-10-07T10:50:10.257Z" }, - { url = "https://files.pythonhosted.org/packages/6e/b5/334473b6d2810df84db67f03d4f666acacfc538512c2d2a254074fee0889/pydantic_core-2.41.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e97ccfaf0aaf67d55de5085b0ed0d994f57747d9d03f2de5cc9847ca737b08", size = 1935786, upload-time = "2025-10-07T10:50:12.333Z" }, - { url = "https://files.pythonhosted.org/packages/ea/5e/45513e4dc621f47397cfa5fef12ba8fa5e8b1c4c07f2ff2a5fef8ff81b25/pydantic_core-2.41.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34df1fe8fea5d332484a763702e8b6a54048a9d4fe6ccf41e34a128238e01f52", size = 1971995, upload-time = "2025-10-07T10:50:14.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/e3/f1797c168e5f52b973bed1c585e99827a22d5e579d1ed57d51bc15b14633/pydantic_core-2.41.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:421b5595f845842fc093f7250e24ee395f54ca62d494fdde96f43ecf9228ae01", size = 2191264, upload-time = "2025-10-07T10:50:15.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e1/24ef4c3b4ab91c21c3a09a966c7d2cffe101058a7bfe5cc8b2c7c7d574e2/pydantic_core-2.41.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dce8b22663c134583aaad24827863306a933f576c79da450be3984924e2031d1", size = 2152430, upload-time = "2025-10-07T10:50:18.018Z" }, - { url = "https://files.pythonhosted.org/packages/35/74/70c1e225d67f7ef3fdba02c506d9011efaf734020914920b2aa3d1a45e61/pydantic_core-2.41.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:300a9c162fea9906cc5c103893ca2602afd84f0ec90d3be36f4cc360125d22e1", size = 2324691, upload-time = "2025-10-07T10:50:19.801Z" }, - { url = "https://files.pythonhosted.org/packages/c8/bf/dd4d21037c8bef0d8cce90a86a3f2dcb011c30086db2a10113c3eea23eba/pydantic_core-2.41.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e019167628f6e6161ae7ab9fb70f6d076a0bf0d55aa9b20833f86a320c70dd65", size = 2324493, upload-time = "2025-10-07T10:50:21.568Z" }, - { url = "https://files.pythonhosted.org/packages/7e/78/3093b334e9c9796c8236a4701cd2ddef1c56fb0928fe282a10c797644380/pydantic_core-2.41.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:13ab9cc2de6f9d4ab645a050ae5aee61a2424ac4d3a16ba23d4c2027705e0301", size = 2146156, upload-time = "2025-10-07T10:50:23.475Z" }, { url = "https://files.pythonhosted.org/packages/e6/6c/fa3e45c2b054a1e627a89a364917f12cbe3abc3e91b9004edaae16e7b3c5/pydantic_core-2.41.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:af2385d3f98243fb733862f806c5bb9122e5fba05b373e3af40e3c82d711cef1", size = 2112094, upload-time = "2025-10-07T10:50:25.513Z" }, { url = "https://files.pythonhosted.org/packages/e5/17/7eebc38b4658cc8e6902d0befc26388e4c2a5f2e179c561eeb43e1922c7b/pydantic_core-2.41.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6550617a0c2115be56f90c31a5370261d8ce9dbf051c3ed53b51172dd34da696", size = 1935300, upload-time = "2025-10-07T10:50:27.715Z" }, { url = "https://files.pythonhosted.org/packages/2b/00/9fe640194a1717a464ab861d43595c268830f98cb1e2705aa134b3544b70/pydantic_core-2.41.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc17b6ecf4983d298686014c92ebc955a9f9baf9f57dad4065e7906e7bee6222", size = 1970417, upload-time = "2025-10-07T10:50:29.573Z" }, @@ -2289,12 +1797,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/a9/25/72d8d0e922022bf6f133511ff9aa7b2e516e2b5a515f2829928e6e35924a/pyqwest-0.4.0.tar.gz", hash = "sha256:ba3770790534b89ae97da7423fc4c6a814f0ccf1d1aa2eeafab6730acfb43449", size = 439348, upload-time = "2026-02-03T06:58:13.851Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/6f/79a27f3b4f4cd68f4f7c15165b0550fea5f409e4dbaff294ed17ce592962/pyqwest-0.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:77fa2ca80e5d2684939a57d7d5dd941779d69776daff94b7c1bdad26fd99b683", size = 4977464, upload-time = "2026-02-03T06:57:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/84/4f/9c38225252d25e494cba87688c431ee83d209494a43b51efbcdb8e0a9574/pyqwest-0.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99f2e5c18473ce09c8e6c8c43095424c24aa89785920bf1f31c9a3c14374f947", size = 5361749, upload-time = "2026-02-03T06:57:02.513Z" }, - { url = "https://files.pythonhosted.org/packages/7c/da/af0a6ce1e6da2c9104763805818829a910571cd01c920e5260ba9d8effa7/pyqwest-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7de77d9e855352538b513a770efc0b2e9361c0eb19de196bc750ff3a4a680c72", size = 5388470, upload-time = "2026-02-03T06:57:04.07Z" }, - { url = "https://files.pythonhosted.org/packages/fe/3e/24d05ecbacc37b6e3caf46e4db6d5d83db62ccefb020bc3cce1f148244d5/pyqwest-0.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1608151150c15b003da453cecfc0713b56bb45801551cb5287b06da1756888ba", size = 5526328, upload-time = "2026-02-03T06:57:05.982Z" }, - { url = "https://files.pythonhosted.org/packages/16/b3/2e81c4e04ccf9a35710efe2a89120e17e1e0b97c030ea8750ef0b0f8550e/pyqwest-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9c616b3a5dbdb129f7af392f5afa5f2ebfa32e8018ad8c0951f8a9601098cdd", size = 5696899, upload-time = "2026-02-03T06:57:07.487Z" }, - { url = "https://files.pythonhosted.org/packages/33/b2/8a2ededaea028ee04f5522a2ce353fc14e6bd1a46140bf4ffc4f56bebfb0/pyqwest-0.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:6a3f855da64aabe57e908d9fa5996352397cc41020385ca283a988edf3f7a6c1", size = 4560972, upload-time = "2026-02-03T06:57:08.85Z" }, { url = "https://files.pythonhosted.org/packages/46/9b/4a412446166e10774ec1f52a6da9b3280040e42e42fde441e6effad79980/pyqwest-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9202c4b2b64ab46351b980bb9fc146e6965f1381d9ca7336655eed369ee07f9f", size = 4974458, upload-time = "2026-02-03T06:57:10.66Z" }, { url = "https://files.pythonhosted.org/packages/45/ac/71683bc5c9059ed718c0354c635987cac09771bc9d55ae13f2da17aea42e/pyqwest-0.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99e11b9d89c29a6342c19b4a861b8f671ab4be09c7e3e0485e2475f7999743bc", size = 5361919, upload-time = "2026-02-03T06:57:12.102Z" }, { url = "https://files.pythonhosted.org/packages/1a/8b/e631572ceb9e80eb4041af6671f8b998ae467f0affc756eb315128a35969/pyqwest-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d451326cb21bf03c8ce6111a9eff1d60651f6e96199f7afe55b05f78db364f4", size = 5388441, upload-time = "2026-02-03T06:57:14.53Z" }, @@ -2313,18 +1815,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/41/8efce20c3446ccbf686b9b18f19de833378fa05bcf65d91bd0a6d4283645/pyqwest-0.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:57cb1568bc5d2ef8e2477a86e8ed271197a37de23ebeacd85927affab71ae41c", size = 5516697, upload-time = "2026-02-03T06:57:37.504Z" }, { url = "https://files.pythonhosted.org/packages/0a/7c/acc63e25f5e571be944c31903361bb775a9ea9b710a41cb687c7e7d84216/pyqwest-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cf9db68993d9defc3174814168709f0c59baf262ae92e35a0e3ea285a207fb0", size = 5699477, upload-time = "2026-02-03T06:57:38.974Z" }, { url = "https://files.pythonhosted.org/packages/02/73/d13a3d0c68b3091e024e8f542368d86a39fb28b56859a725cba38990ca8e/pyqwest-0.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:d7de72d9daa14296468f534be9f6be21f34886992546a75d15a7562f12ae5d9b", size = 4564829, upload-time = "2026-02-03T06:57:41.88Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/44ca41c2ffffc7e60714aaadfe0b81c3f6e5adc86e26336b078a1b1abd08/pyqwest-0.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f687900b48f6058edf38988191e411a1f8c8a420d9e1a9ecda4cafdbcf7d3b9f", size = 4980118, upload-time = "2026-02-03T06:57:43.732Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f8/544ed82c6edd3b85db49ce9e9992441cbfefa8b92a556058174aba0a3f9c/pyqwest-0.4.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdee6edf8a7ebb108619ac99d5c9095d2b3898f21e14d8e02513dad867af7855", size = 5347929, upload-time = "2026-02-03T06:57:45.239Z" }, - { url = "https://files.pythonhosted.org/packages/5b/4b/012e246dee57fab23edb48cdd32119ed39546d5f67cfe1d8ebc6f594e837/pyqwest-0.4.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9157abebd1b31ef72f410be4b7c6d6a9957c9e7b97fd83a8552d8b04c20724", size = 5390422, upload-time = "2026-02-03T06:57:47.018Z" }, - { url = "https://files.pythonhosted.org/packages/79/61/3cb30777c350cf7bef657d1250f19cd7921c14e44719d3eccf2a192e2ffd/pyqwest-0.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5f225d8a473fc96d65bc837c60f4436d06440d42d0479619659746722ac33d45", size = 5512737, upload-time = "2026-02-03T06:57:48.756Z" }, - { url = "https://files.pythonhosted.org/packages/69/1c/9e2137e88b05728f7ce3e52993cd2d53688a8731bcfcded47ae939a6705a/pyqwest-0.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddbba6f5cf91f12bea6ae2dc0c1d9acac45c1ab6f3b28ab4670c2740f5c8d82f", size = 5699482, upload-time = "2026-02-03T06:57:50.808Z" }, - { url = "https://files.pythonhosted.org/packages/ec/05/48c19c9726a4a95886d30ca5374773bd49bf02a39abdc46504d55716ae18/pyqwest-0.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:dcbecc278646a88f1b51199050294c36ec7272696d2c317663d00a9e1f1a33fc", size = 4565677, upload-time = "2026-02-03T06:57:52.454Z" }, - { url = "https://files.pythonhosted.org/packages/39/9a/39f66574406bd06e73f2fc69d8b1c3802218127b4ec80b3b2b2a2ea24f6b/pyqwest-0.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8eab7213cc8f0fe0212bf0f77b73cec0b2cfad2a8c3d2c5c57d4166d4c429129", size = 4972879, upload-time = "2026-02-03T06:57:54.036Z" }, - { url = "https://files.pythonhosted.org/packages/d8/76/32e81cbaede301fa7a446a7a98d53eef2488b4bdf65c2204b206ed2146f8/pyqwest-0.4.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc4c27b8a84ceb0dbfd198f3878c5e36ab610749c478cf13e91a989913c5d873", size = 5349481, upload-time = "2026-02-03T06:57:55.562Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3c/3a8e36e6ae92b4eaf664a5fa054164455f68180fe834bfceed2f8eef8d3b/pyqwest-0.4.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32b9ee248e1f8b1a1dd2a8ae808a0dd870eba6422a483e154f8a326d69666b5", size = 5383775, upload-time = "2026-02-03T06:57:57.564Z" }, - { url = "https://files.pythonhosted.org/packages/f2/92/7d450c24b21b048f6291f6bb382817305e38f3612aa77d1f3a2f8f7675e7/pyqwest-0.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bae8833afa0d2a6a0dade62b8ed0048336de36481f3d3aeba284fd88ac29a27c", size = 5511843, upload-time = "2026-02-03T06:57:59.05Z" }, - { url = "https://files.pythonhosted.org/packages/33/a8/136642b402b74d3aa049d8e55e589481179940d95af7a2bb79dcf6fe393e/pyqwest-0.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5e7066ec5e70648abf851980f6e4cb392ac828e22d3cf39625a13b533aff5142", size = 5693532, upload-time = "2026-02-03T06:58:00.978Z" }, - { url = "https://files.pythonhosted.org/packages/de/fc/db26a325acbf7111f1429399ae021f1dd8927bcaacd6c835c94c82d3a22f/pyqwest-0.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:75caf851cbf063d867d207b356e67bdd4cf17ea59c06786359a3eaf9975340ec", size = 4566651, upload-time = "2026-02-03T06:58:02.504Z" }, { url = "https://files.pythonhosted.org/packages/3f/0e/966151678bb4759dd1b4c39ef00aaf9fd76f2088f9773e219c38a116b13a/pyqwest-0.4.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:44cb28ae3e6183cb37e305ecf5dace2fb3b05468794bdc747b19fc2a5d7cac4e", size = 4975514, upload-time = "2026-02-03T06:58:03.994Z" }, { url = "https://files.pythonhosted.org/packages/29/80/9dc3856af17111fdbf17d3bafcb8f1928fb6393a9e0378e277d17816b4dc/pyqwest-0.4.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:445cc85401058d74bc3d85ff158a9b9168b955b8375193bb3d0d5fddeaea1ca6", size = 5358554, upload-time = "2026-02-03T06:58:05.52Z" }, { url = "https://files.pythonhosted.org/packages/4d/4a/1dd4f3105365def5a4ebe1869c5ca960b3d5e6cb4aa877e0642da2c37ccd/pyqwest-0.4.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5089f47502740f2cd79f6ebd12619bfd90a72a683cf5e24032d0357ef89f427", size = 5384501, upload-time = "2026-02-03T06:58:07.157Z" }, @@ -2339,12 +1829,10 @@ version = "8.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ @@ -2356,7 +1844,6 @@ name = "pytest-asyncio" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] @@ -2422,9 +1909,6 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, @@ -2434,9 +1918,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, - { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, ] [[package]] @@ -2445,15 +1926,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, @@ -2483,24 +1955,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] @@ -2512,16 +1966,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, @@ -2554,21 +1998,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, - { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, - { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, - { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, - { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, - { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, - { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, @@ -2596,23 +2025,6 @@ version = "2026.3.32" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/81/93/5ab3e899c47fa7994e524447135a71cd121685a35c8fe35029005f8b236f/regex-2026.3.32.tar.gz", hash = "sha256:f1574566457161678297a116fa5d1556c5a4159d64c5ff7c760e7c564bf66f16", size = 415605, upload-time = "2026-03-28T21:49:22.012Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/87/ae29a505fdfcec85978f35d30e6de7c0ae37eaf7c287f6e88abd04be27b3/regex-2026.3.32-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:462a041d2160090553572f6bb0be417ab9bb912a08de54cb692829c871ee88c1", size = 489575, upload-time = "2026-03-28T21:45:27.167Z" }, - { url = "https://files.pythonhosted.org/packages/f9/fd/7a56c6a86213e321a309161673667091991630287d7490c5e9ec3db29607/regex-2026.3.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3c6f6b027d10f84bfe65049028892b5740878edd9eae5fea0d1710b09b1d257", size = 291288, upload-time = "2026-03-28T21:45:30.886Z" }, - { url = "https://files.pythonhosted.org/packages/48/2f/ac2b481011b23f79994d4d80df03d9feccb64fbfc7bbe8dad2c3e8efc50c/regex-2026.3.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:879ae91f2928a13f01a55cfa168acedd2b02b11b4cd8b5bb9223e8cde777ca52", size = 289336, upload-time = "2026-03-28T21:45:32.631Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a2/cf7dfef7a4182e84acbe8919ce7ff50e3545007c2743219e92271b2fbc1c/regex-2026.3.32-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:887a9fa74418d74d645281ee0edcf60694053bd1bc2ebc49eb5e66bfffc6d107", size = 786358, upload-time = "2026-03-28T21:45:34.025Z" }, - { url = "https://files.pythonhosted.org/packages/fb/cb/42bfeb4597206e3171e70c973ca1d39190b48f6cda7546c25f9cb283285f/regex-2026.3.32-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d571f0b2eec3513734ea31a16ce0f7840c0b85a98e7edfa0e328ed144f9ef78f", size = 854179, upload-time = "2026-03-28T21:45:35.713Z" }, - { url = "https://files.pythonhosted.org/packages/90/d8/9f4a7d7edffe7117de23b94696c52065b68e70267d71576d74429d598d9b/regex-2026.3.32-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ada7bd5bb6511d12177a7b00416ce55caee49fbf8c268f26b909497b534cacb", size = 898810, upload-time = "2026-03-28T21:45:37.435Z" }, - { url = "https://files.pythonhosted.org/packages/05/e6/80335c06ddf7fd7a28b97402ebe1ea4fe80a3aa162fba0f7364175f625d1/regex-2026.3.32-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:918db4e34a7ef3d0beee913fa54b34231cc3424676f1c19bdb85f01828d3cd37", size = 790605, upload-time = "2026-03-28T21:45:39.207Z" }, - { url = "https://files.pythonhosted.org/packages/38/0e/91436a89c1636090903d753d90b076784b11b8c67b79b3bde9851a45c4d7/regex-2026.3.32-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:69a847a6ffaa86e8af7b9e7037606e05a6f663deec516ad851e8e05d9908d16a", size = 786550, upload-time = "2026-03-28T21:45:40.993Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fc/ea7364b5e9abd220cebf547f2f8a42044878e9d8b02b3a652f8b807c0cbc/regex-2026.3.32-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2c8d402ea3dfe674288fe3962016affd33b5b27213d2b5db1823ffa4de524c57", size = 770223, upload-time = "2026-03-28T21:45:42.802Z" }, - { url = "https://files.pythonhosted.org/packages/3b/86/aff4ad741e914cc493e7500431cdf14e51bc808b14f1f205469d353a970b/regex-2026.3.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d6b39a2cc5625bbc4fda18919a891eab9aab934eecf83660a90ce20c53621a9a", size = 774436, upload-time = "2026-03-28T21:45:44.212Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e7/060779f504c92320f75b90caab4e57324816020986c27f57414b0a1ebcc9/regex-2026.3.32-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f7cc00089b4c21847852c0ad76fb3680f9833b855a0d30bcec94211c435bff6b", size = 849400, upload-time = "2026-03-28T21:45:46.2Z" }, - { url = "https://files.pythonhosted.org/packages/c8/8e/6544b27f70bfd14e9c50ff5527027acc9b8f9830d352a746f843da7b0627/regex-2026.3.32-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:fd03e38068faeef937cc6761a250a4aaa015564bd0d61481fefcf15586d31825", size = 757934, upload-time = "2026-03-28T21:45:47.962Z" }, - { url = "https://files.pythonhosted.org/packages/bc/6f/abf2234b3f51da1e693f13bb85e7dbb3bbdd07c04e12e0e105b9bc6006a6/regex-2026.3.32-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e006ea703d5c0f3d112b51ba18af73b58209b954acfe3d8da42eacc9a00e4be6", size = 838479, upload-time = "2026-03-28T21:45:49.845Z" }, - { url = "https://files.pythonhosted.org/packages/db/3c/653f43c3a3643fd221bfaf61ed4a4c8f0ccc25e31a8faa8f1558a892c22c/regex-2026.3.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6980ceb5c1049d4878632f08ba0bf7234c30e741b0dc9081da0f86eca13189d3", size = 778478, upload-time = "2026-03-28T21:45:51.574Z" }, - { url = "https://files.pythonhosted.org/packages/88/dd/5e6bd702d7efc3f2a29bf65dfa46f5159653b3c6f846ddf693e1a7f9a739/regex-2026.3.32-cp310-cp310-win32.whl", hash = "sha256:6128dd0793a87287ea1d8bf16b4250dd96316c464ee15953d5b98875a284d41e", size = 266343, upload-time = "2026-03-28T21:45:53.548Z" }, - { url = "https://files.pythonhosted.org/packages/c4/89/39d04329e858956d2db1d08a10f02be8f6837c964663513ac4393158bef9/regex-2026.3.32-cp310-cp310-win_amd64.whl", hash = "sha256:5aa78c857c1731bdd9863923ffadc816d823edf475c7db6d230c28b53b7bdb5e", size = 278632, upload-time = "2026-03-28T21:45:55.604Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d8/c7e9ff3c2648408f4cda7224e195ad7a0d68724225d8d9a55eca9055504f/regex-2026.3.32-cp310-cp310-win_arm64.whl", hash = "sha256:34c905a721ddee0f84c99e3e3b59dd4a5564a6fe338222bc89dd4d4df166115c", size = 270593, upload-time = "2026-03-28T21:45:56.994Z" }, { url = "https://files.pythonhosted.org/packages/92/c1/c68163a6ce455996db71e249a65234b1c9f79a914ea2108c6c9af9e1812a/regex-2026.3.32-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d7855f5e59fcf91d0c9f4a51dc5d8847813832a2230c3e8e35912ccf20baaa2", size = 489568, upload-time = "2026-03-28T21:45:58.791Z" }, { url = "https://files.pythonhosted.org/packages/96/9c/0bdd47733b832b5caa11e63df14dccdb311b41ab33c1221e249af4421f8f/regex-2026.3.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:18eb45f711e942c27dbed4109830bd070d8d618e008d0db39705f3f57070a4c6", size = 291287, upload-time = "2026-03-28T21:46:00.46Z" }, { url = "https://files.pythonhosted.org/packages/e1/ff/1977a595f15f8dc355f9cebd875dab67f3faeca1f36b905fe53305bbcaed/regex-2026.3.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed3b8281c5d0944d939c82db4ec2300409dd69ee087f7a75a94f2e301e855fb4", size = 289325, upload-time = "2026-03-28T21:46:02.285Z" }, @@ -2677,38 +2089,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/06/0fa9daca59d07b6aabd8e0468d3b86fd578576a157206fbcddbfc2298f7d/regex-2026.3.32-cp313-cp313t-win32.whl", hash = "sha256:9cf7036dfa2370ccc8651521fcbb40391974841119e9982fa312b552929e6c85", size = 269892, upload-time = "2026-03-28T21:47:59.674Z" }, { url = "https://files.pythonhosted.org/packages/13/47/77f16b5ad9f10ca574f03d84a354b359b0ac33f85054f2f2daafc9f7b807/regex-2026.3.32-cp313-cp313t-win_amd64.whl", hash = "sha256:c940e00e8d3d10932c929d4b8657c2ea47d2560f31874c3e174c0d3488e8b865", size = 281318, upload-time = "2026-03-28T21:48:01.562Z" }, { url = "https://files.pythonhosted.org/packages/c6/47/db4446faaea8d01c8315c9c89c7dc6abbb3305e8e712e9b23936095c4d58/regex-2026.3.32-cp313-cp313t-win_arm64.whl", hash = "sha256:ace48c5e157c1e58b7de633c5e257285ce85e567ac500c833349c363b3df69d4", size = 272366, upload-time = "2026-03-28T21:48:03.748Z" }, - { url = "https://files.pythonhosted.org/packages/32/68/ff024bf6131b7446a791a636dbbb7fa732d586f33b276d84b3460ea49393/regex-2026.3.32-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a416ee898ecbc5d8b283223b4cf4d560f93244f6f7615c1bd67359744b00c166", size = 490430, upload-time = "2026-03-28T21:48:05.654Z" }, - { url = "https://files.pythonhosted.org/packages/61/72/039d9164817ee298f2a2d0246001afe662241dcbec0eedd1fe03e2a2555e/regex-2026.3.32-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d76d62909bfb14521c3f7cfd5b94c0c75ec94b0a11f647d2f604998962ec7b6c", size = 291948, upload-time = "2026-03-28T21:48:07.666Z" }, - { url = "https://files.pythonhosted.org/packages/06/9d/77f684d90ffe3e99b828d3cabb87a0f1601d2b9decd1333ff345809b1d02/regex-2026.3.32-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:631f7d95c83f42bccfe18946a38ad27ff6b6717fb4807e60cf24860b5eb277fc", size = 289786, upload-time = "2026-03-28T21:48:09.562Z" }, - { url = "https://files.pythonhosted.org/packages/83/70/bd76069a0304e924682b2efd8683a01617a7e1da9b651af73039d8da76a4/regex-2026.3.32-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12917c6c6813ffcdfb11680a04e4d63c5532b88cf089f844721c5f41f41a63ad", size = 796672, upload-time = "2026-03-28T21:48:11.568Z" }, - { url = "https://files.pythonhosted.org/packages/80/31/c2d7d9a5671e111a2c16d57e0cb03e1ce35b28a115901590528aa928bb5b/regex-2026.3.32-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e221b615f83b15887636fcb90ed21f1a19541366f8b7ba14ba1ad8304f4ded4", size = 866556, upload-time = "2026-03-28T21:48:14.081Z" }, - { url = "https://files.pythonhosted.org/packages/d7/b9/9921a31931d0bc3416ac30205471e0e2ed60dcbd16fc922bbd69b427322b/regex-2026.3.32-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4f9ae4755fa90f1dc2d0d393d572ebc134c0fe30fcfc0ab7e67c1db15f192041", size = 912787, upload-time = "2026-03-28T21:48:16.548Z" }, - { url = "https://files.pythonhosted.org/packages/41/ab/2c1bc8ab99f63cdabdbc7823af8f4cfcd6ddbb2babf01861826c3f1ad44d/regex-2026.3.32-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a094e9dcafedfb9d333db5cf880304946683f43a6582bb86688f123335122929", size = 800879, upload-time = "2026-03-28T21:48:18.971Z" }, - { url = "https://files.pythonhosted.org/packages/49/e5/0be716eb2c0b2ae3a439e44432534e82b2f81848af64cb21c0473ad8ae46/regex-2026.3.32-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c1cecea3e477af105f32ef2119b8d895f297492e41d317e60d474bc4bffd62ff", size = 776332, upload-time = "2026-03-28T21:48:21.163Z" }, - { url = "https://files.pythonhosted.org/packages/26/80/114a61bd25dec7d1070930eaef82aadf9b05961a37629e7cca7bc3fc2257/regex-2026.3.32-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f26262900edd16272b6360014495e8d68379c6c6e95983f9b7b322dc928a1194", size = 786384, upload-time = "2026-03-28T21:48:23.277Z" }, - { url = "https://files.pythonhosted.org/packages/0c/78/be0a6531f8db426e8e60d6356aeef8e9cc3f541655a648c4968b63c87a88/regex-2026.3.32-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1cb22fa9ee6a0acb22fc9aecce5f9995fe4d2426ed849357d499d62608fbd7f9", size = 861381, upload-time = "2026-03-28T21:48:25.371Z" }, - { url = "https://files.pythonhosted.org/packages/45/b1/e5076fbe45b8fb39672584b1b606d512f5bd3a43155be68a95f6b88c1fc5/regex-2026.3.32-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:9b9118a78e031a2e4709cd2fcc3028432e89b718db70073a8da574c249b5b249", size = 765434, upload-time = "2026-03-28T21:48:27.494Z" }, - { url = "https://files.pythonhosted.org/packages/a3/da/fd65d68b897f8b52b1390d20d776fa753582484724a9cb4f4c26de657ae5/regex-2026.3.32-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b193ed199848aa96618cd5959c1582a0bf23cd698b0b900cb0ffe81b02c8659c", size = 851501, upload-time = "2026-03-28T21:48:29.884Z" }, - { url = "https://files.pythonhosted.org/packages/e8/d6/1e9c991c32022a9312e9124cc974961b3a2501338de2cd1cce75a3612d7a/regex-2026.3.32-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:10fb2aaae1aaadf7d43c9f3c2450404253697bf8b9ce360bd5418d1d16292298", size = 788076, upload-time = "2026-03-28T21:48:32.025Z" }, - { url = "https://files.pythonhosted.org/packages/f0/5b/b23c72f6d607cbb24ef42acf0c7c2ef4eee1377a9f7ba43b312f889edfbb/regex-2026.3.32-cp314-cp314-win32.whl", hash = "sha256:110ba4920721374d16c4c8ea7ce27b09546d43e16aea1d7f43681b5b8f80ba61", size = 272255, upload-time = "2026-03-28T21:48:34.355Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ec/32bbcc42366097a8cea2c481e02964be6c6fa5ccfb0fa9581686af0bec5f/regex-2026.3.32-cp314-cp314-win_amd64.whl", hash = "sha256:245667ad430745bae6a1e41081872d25819d86fbd9e0eec485ba00d9f78ad43d", size = 281160, upload-time = "2026-03-28T21:48:36.588Z" }, - { url = "https://files.pythonhosted.org/packages/6c/e4/89038a028cb68e719fa03ab1ad603649fc199bcda12270d2ac7b471b8f5d/regex-2026.3.32-cp314-cp314-win_arm64.whl", hash = "sha256:1ca02ff0ef33e9d8276a1fcd6d90ff6ea055a32c9149c0050b5b67e26c6d2c51", size = 273688, upload-time = "2026-03-28T21:48:38.976Z" }, - { url = "https://files.pythonhosted.org/packages/30/6e/87caccd608837a1fa4f8c7edc48e206103452b9bbc94fc724fa39340e807/regex-2026.3.32-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:51fb7e26f91f9091fd8ec6a946f99b15d3bc3667cb5ddc73dd6cb2222dd4a1cc", size = 494506, upload-time = "2026-03-28T21:48:41.327Z" }, - { url = "https://files.pythonhosted.org/packages/16/53/a922e6b24694d70bdd68fc3fd076950e15b1b418cff9d2cc362b3968d86f/regex-2026.3.32-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:51a93452034d671b0e21b883d48ea66c5d6a05620ee16a9d3f229e828568f3f0", size = 293986, upload-time = "2026-03-28T21:48:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/60/e4/0cb32203c1aebad0577fcd5b9af1fe764869e617d5234bc6a0ad284299ea/regex-2026.3.32-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:03c2ebd15ff51e7b13bb3dc28dd5ac18cd39e59ebb40430b14ae1a19e833cff1", size = 292677, upload-time = "2026-03-28T21:48:45.772Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f8/5006b70291469d4174dd66ad162802e2f68419c0f2a7952d0c76c1288cfa/regex-2026.3.32-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5bf2f3c2c5bd8360d335c7dcd4a9006cf1dabae063ee2558ee1b07bbc8a20d88", size = 810661, upload-time = "2026-03-28T21:48:48.147Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9b/438763a20d22cd1f65f95c8f030dd25df2d80a941068a891d21a5f240456/regex-2026.3.32-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a4a3189a99ecdd1c13f42513ab3fc7fa8311b38ba7596dd98537acb8cd9acc3", size = 872156, upload-time = "2026-03-28T21:48:50.739Z" }, - { url = "https://files.pythonhosted.org/packages/6c/5b/1341287887ac982ed9f5f60125e440513ffe354aa7e3681940495af7c12a/regex-2026.3.32-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3c0bbfbd38506e1ea96a85da6782577f06239cb9fcf9696f1ea537c980c0680b", size = 916749, upload-time = "2026-03-28T21:48:53.57Z" }, - { url = "https://files.pythonhosted.org/packages/42/e2/1d2b48b8e94debfffc6fefb84d2a86a178cc208652a1d6493d5f29821c70/regex-2026.3.32-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8aaf8ee8f34b677f90742ca089b9c83d64bdc410528767273c816a863ed57327", size = 814788, upload-time = "2026-03-28T21:48:55.905Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d9/7dacb34c43adaeb954518d851f3e5d3ce495ac00a9d6010e3b4b59917c4a/regex-2026.3.32-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ea568832eca219c2be1721afa073c1c9eb8f98a9733fdedd0a9747639fc22a5", size = 786594, upload-time = "2026-03-28T21:48:58.404Z" }, - { url = "https://files.pythonhosted.org/packages/ea/72/28295068c92dbd6d3ce4fd22554345cf504e957cc57dadeda4a64fa86a57/regex-2026.3.32-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e4c8fa46aad1a11ae2f8fcd1c90b9d55e18925829ac0d98c5bb107f93351745", size = 800167, upload-time = "2026-03-28T21:49:01.226Z" }, - { url = "https://files.pythonhosted.org/packages/ca/17/b10745adeca5b8d52da050e7c746137f5d01dabc6dbbe6e8d9d821dc65c1/regex-2026.3.32-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cec365d44835b043d7b3266487797639d07d621bec9dc0ea224b00775797cc1", size = 865906, upload-time = "2026-03-28T21:49:03.484Z" }, - { url = "https://files.pythonhosted.org/packages/45/9d/1acbcce765044ac0c87f453f4876e0897f7a61c10315262f960184310798/regex-2026.3.32-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:09e26cad1544d856da85881ad292797289e4406338afe98163f3db9f7fac816c", size = 772642, upload-time = "2026-03-28T21:49:06.811Z" }, - { url = "https://files.pythonhosted.org/packages/24/41/1ef8b4811355ad7b9d7579d3aeca00f18b7bc043ace26c8c609b9287346d/regex-2026.3.32-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:6062c4ef581a3e9e503dccf4e1b7f2d33fdc1c13ad510b287741ac73bc4c6b27", size = 856927, upload-time = "2026-03-28T21:49:09.373Z" }, - { url = "https://files.pythonhosted.org/packages/97/b1/0dc1d361be80ec1b8b707ada041090181133a7a29d438e432260a4b26f9a/regex-2026.3.32-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88ebc0783907468f17fca3d7821b30f9c21865a721144eb498cb0ff99a67bcac", size = 801910, upload-time = "2026-03-28T21:49:11.818Z" }, - { url = "https://files.pythonhosted.org/packages/b5/db/1a23f767fa250844772a9464306d34e0fafe2c317303b88a1415096b6324/regex-2026.3.32-cp314-cp314t-win32.whl", hash = "sha256:e480d3dac06c89bc2e0fd87524cc38c546ac8b4a38177650745e64acbbcfdeba", size = 275714, upload-time = "2026-03-28T21:49:14.528Z" }, - { url = "https://files.pythonhosted.org/packages/c2/2b/616d31b125ca76079d74d6b1d84ec0860ffdb41c379151135d06e35a8633/regex-2026.3.32-cp314-cp314t-win_amd64.whl", hash = "sha256:67015a8162d413af9e3309d9a24e385816666fbf09e48e3ec43342c8536f7df6", size = 285722, upload-time = "2026-03-28T21:49:16.642Z" }, - { url = "https://files.pythonhosted.org/packages/7e/91/043d9a00d6123c5fa22a3dc96b10445ce434a8110e1d5e53efb01f243c8b/regex-2026.3.32-cp314-cp314t-win_arm64.whl", hash = "sha256:1a6ac1ed758902e664e0d95c1ee5991aa6fb355423f378ed184c6ec47a1ec0e9", size = 275700, upload-time = "2026-03-28T21:49:19.348Z" }, +] + +[[package]] +name = "renderers" +version = "0.1.8.dev49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastokens" }, + { name = "jinja2" }, + { name = "numpy" }, + { name = "openai" }, + { name = "openai-harmony" }, + { name = "prime-pydantic-config" }, + { name = "tiktoken" }, + { name = "transformers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/03/06f9422abecfbe24306f3a6f7a09229e0af2decc5d07157f816251cf9d25/renderers-0.1.8.dev49.tar.gz", hash = "sha256:35c88a010d66c92615ef91531ced360f1155556ec489e699c471d2d7250cf3fb", size = 323395, upload-time = "2026-06-19T01:47:16.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/b9/dc980780f735c07800ffca49b56af72d6a183df58a383d0e6cd7ae3c60e1/renderers-0.1.8.dev49-py3-none-any.whl", hash = "sha256:71738ed203445cfb3763e953f6dc6bd8d51f6fe874b316b521329fd0d36af0e2", size = 172028, upload-time = "2026-06-19T01:47:15.499Z" }, ] [[package]] @@ -2745,20 +2144,6 @@ version = "0.27.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/ed/3aef893e2dd30e77e35d20d4ddb45ca459db59cead748cad9796ad479411/rpds_py-0.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:68afeec26d42ab3b47e541b272166a0b4400313946871cba3ed3a4fc0cab1cef", size = 371606, upload-time = "2025-08-27T12:12:25.189Z" }, - { url = "https://files.pythonhosted.org/packages/6d/82/9818b443e5d3eb4c83c3994561387f116aae9833b35c484474769c4a8faf/rpds_py-0.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74e5b2f7bb6fa38b1b10546d27acbacf2a022a8b5543efb06cfebc72a59c85be", size = 353452, upload-time = "2025-08-27T12:12:27.433Z" }, - { url = "https://files.pythonhosted.org/packages/99/c7/d2a110ffaaa397fc6793a83c7bd3545d9ab22658b7cdff05a24a4535cc45/rpds_py-0.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9024de74731df54546fab0bfbcdb49fae19159ecaecfc8f37c18d2c7e2c0bd61", size = 381519, upload-time = "2025-08-27T12:12:28.719Z" }, - { url = "https://files.pythonhosted.org/packages/5a/bc/e89581d1f9d1be7d0247eaef602566869fdc0d084008ba139e27e775366c/rpds_py-0.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31d3ebadefcd73b73928ed0b2fd696f7fefda8629229f81929ac9c1854d0cffb", size = 394424, upload-time = "2025-08-27T12:12:30.207Z" }, - { url = "https://files.pythonhosted.org/packages/ac/2e/36a6861f797530e74bb6ed53495f8741f1ef95939eed01d761e73d559067/rpds_py-0.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2e7f8f169d775dd9092a1743768d771f1d1300453ddfe6325ae3ab5332b4657", size = 523467, upload-time = "2025-08-27T12:12:31.808Z" }, - { url = "https://files.pythonhosted.org/packages/c4/59/c1bc2be32564fa499f988f0a5c6505c2f4746ef96e58e4d7de5cf923d77e/rpds_py-0.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d905d16f77eb6ab2e324e09bfa277b4c8e5e6b8a78a3e7ff8f3cdf773b4c013", size = 402660, upload-time = "2025-08-27T12:12:33.444Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ec/ef8bf895f0628dd0a59e54d81caed6891663cb9c54a0f4bb7da918cb88cf/rpds_py-0.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50c946f048209e6362e22576baea09193809f87687a95a8db24e5fbdb307b93a", size = 384062, upload-time = "2025-08-27T12:12:34.857Z" }, - { url = "https://files.pythonhosted.org/packages/69/f7/f47ff154be8d9a5e691c083a920bba89cef88d5247c241c10b9898f595a1/rpds_py-0.27.1-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:3deab27804d65cd8289eb814c2c0e807c4b9d9916c9225e363cb0cf875eb67c1", size = 401289, upload-time = "2025-08-27T12:12:36.085Z" }, - { url = "https://files.pythonhosted.org/packages/3b/d9/ca410363efd0615814ae579f6829cafb39225cd63e5ea5ed1404cb345293/rpds_py-0.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b61097f7488de4be8244c89915da8ed212832ccf1e7c7753a25a394bf9b1f10", size = 417718, upload-time = "2025-08-27T12:12:37.401Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a0/8cb5c2ff38340f221cc067cc093d1270e10658ba4e8d263df923daa18e86/rpds_py-0.27.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a3f29aba6e2d7d90528d3c792555a93497fe6538aa65eb675b44505be747808", size = 558333, upload-time = "2025-08-27T12:12:38.672Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8c/1b0de79177c5d5103843774ce12b84caa7164dfc6cd66378768d37db11bf/rpds_py-0.27.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd6cd0485b7d347304067153a6dc1d73f7d4fd995a396ef32a24d24b8ac63ac8", size = 589127, upload-time = "2025-08-27T12:12:41.48Z" }, - { url = "https://files.pythonhosted.org/packages/c8/5e/26abb098d5e01266b0f3a2488d299d19ccc26849735d9d2b95c39397e945/rpds_py-0.27.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f4461bf931108c9fa226ffb0e257c1b18dc2d44cd72b125bec50ee0ab1248a9", size = 554899, upload-time = "2025-08-27T12:12:42.925Z" }, - { url = "https://files.pythonhosted.org/packages/de/41/905cc90ced13550db017f8f20c6d8e8470066c5738ba480d7ba63e3d136b/rpds_py-0.27.1-cp310-cp310-win32.whl", hash = "sha256:ee5422d7fb21f6a00c1901bf6559c49fee13a5159d0288320737bbf6585bd3e4", size = 217450, upload-time = "2025-08-27T12:12:44.813Z" }, - { url = "https://files.pythonhosted.org/packages/75/3d/6bef47b0e253616ccdf67c283e25f2d16e18ccddd38f92af81d5a3420206/rpds_py-0.27.1-cp310-cp310-win_amd64.whl", hash = "sha256:3e039aabf6d5f83c745d5f9a0a381d031e9ed871967c0a5c38d201aca41f3ba1", size = 228447, upload-time = "2025-08-27T12:12:46.204Z" }, { url = "https://files.pythonhosted.org/packages/b5/c1/7907329fbef97cbd49db6f7303893bd1dd5a4a3eae415839ffdfb0762cae/rpds_py-0.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:be898f271f851f68b318872ce6ebebbc62f303b654e43bf72683dbdc25b7c881", size = 371063, upload-time = "2025-08-27T12:12:47.856Z" }, { url = "https://files.pythonhosted.org/packages/11/94/2aab4bc86228bcf7c48760990273653a4900de89c7537ffe1b0d6097ed39/rpds_py-0.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:62ac3d4e3e07b58ee0ddecd71d6ce3b1637de2d373501412df395a0ec5f9beb5", size = 353210, upload-time = "2025-08-27T12:12:49.187Z" }, { url = "https://files.pythonhosted.org/packages/3a/57/f5eb3ecf434342f4f1a46009530e93fd201a0b5b83379034ebdb1d7c1a58/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4708c5c0ceb2d034f9991623631d3d23cb16e65c83736ea020cdbe28d57c0a0e", size = 381636, upload-time = "2025-08-27T12:12:50.492Z" }, @@ -2818,48 +2203,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, - { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, - { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, - { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, - { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, - { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, - { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, - { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, - { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, - { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, - { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, - { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, - { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, - { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, - { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, - { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, - { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, - { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, - { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, - { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, - { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, - { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, - { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, - { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, - { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, - { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, - { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, - { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, - { url = "https://files.pythonhosted.org/packages/d5/63/b7cc415c345625d5e62f694ea356c58fb964861409008118f1245f8c3347/rpds_py-0.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7ba22cb9693df986033b91ae1d7a979bc399237d45fccf875b76f62bb9e52ddf", size = 371360, upload-time = "2025-08-27T12:15:29.218Z" }, - { url = "https://files.pythonhosted.org/packages/e5/8c/12e1b24b560cf378b8ffbdb9dc73abd529e1adcfcf82727dfd29c4a7b88d/rpds_py-0.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b640501be9288c77738b5492b3fd3abc4ba95c50c2e41273c8a1459f08298d3", size = 353933, upload-time = "2025-08-27T12:15:30.837Z" }, - { url = "https://files.pythonhosted.org/packages/9b/85/1bb2210c1f7a1b99e91fea486b9f0f894aa5da3a5ec7097cbad7dec6d40f/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb08b65b93e0c6dd70aac7f7890a9c0938d5ec71d5cb32d45cf844fb8ae47636", size = 382962, upload-time = "2025-08-27T12:15:32.348Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c9/a839b9f219cf80ed65f27a7f5ddbb2809c1b85c966020ae2dff490e0b18e/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d7ff07d696a7a38152ebdb8212ca9e5baab56656749f3d6004b34ab726b550b8", size = 394412, upload-time = "2025-08-27T12:15:33.839Z" }, - { url = "https://files.pythonhosted.org/packages/02/2d/b1d7f928b0b1f4fc2e0133e8051d199b01d7384875adc63b6ddadf3de7e5/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb7c72262deae25366e3b6c0c0ba46007967aea15d1eea746e44ddba8ec58dcc", size = 523972, upload-time = "2025-08-27T12:15:35.377Z" }, - { url = "https://files.pythonhosted.org/packages/a9/af/2cbf56edd2d07716df1aec8a726b3159deb47cb5c27e1e42b71d705a7c2f/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b002cab05d6339716b03a4a3a2ce26737f6231d7b523f339fa061d53368c9d8", size = 403273, upload-time = "2025-08-27T12:15:37.051Z" }, - { url = "https://files.pythonhosted.org/packages/c0/93/425e32200158d44ff01da5d9612c3b6711fe69f606f06e3895511f17473b/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23f6b69d1c26c4704fec01311963a41d7de3ee0570a84ebde4d544e5a1859ffc", size = 385278, upload-time = "2025-08-27T12:15:38.571Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1a/1a04a915ecd0551bfa9e77b7672d1937b4b72a0fc204a17deef76001cfb2/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:530064db9146b247351f2a0250b8f00b289accea4596a033e94be2389977de71", size = 402084, upload-time = "2025-08-27T12:15:40.529Z" }, - { url = "https://files.pythonhosted.org/packages/51/f7/66585c0fe5714368b62951d2513b684e5215beaceab2c6629549ddb15036/rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b90b0496570bd6b0321724a330d8b545827c4df2034b6ddfc5f5275f55da2ad", size = 419041, upload-time = "2025-08-27T12:15:42.191Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7e/83a508f6b8e219bba2d4af077c35ba0e0cdd35a751a3be6a7cba5a55ad71/rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:879b0e14a2da6a1102a3fc8af580fc1ead37e6d6692a781bd8c83da37429b5ab", size = 560084, upload-time = "2025-08-27T12:15:43.839Z" }, - { url = "https://files.pythonhosted.org/packages/66/66/bb945683b958a1b19eb0fe715594630d0f36396ebdef4d9b89c2fa09aa56/rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:0d807710df3b5faa66c731afa162ea29717ab3be17bdc15f90f2d9f183da4059", size = 590115, upload-time = "2025-08-27T12:15:46.647Z" }, - { url = "https://files.pythonhosted.org/packages/12/00/ccfaafaf7db7e7adace915e5c2f2c2410e16402561801e9c7f96683002d3/rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3adc388fc3afb6540aec081fa59e6e0d3908722771aa1e37ffe22b220a436f0b", size = 556561, upload-time = "2025-08-27T12:15:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/e1/b7/92b6ed9aad103bfe1c45df98453dfae40969eef2cb6c6239c58d7e96f1b3/rpds_py-0.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c796c0c1cc68cb08b0284db4229f5af76168172670c74908fdbd4b7d7f515819", size = 229125, upload-time = "2025-08-27T12:15:49.956Z" }, { url = "https://files.pythonhosted.org/packages/0c/ed/e1fba02de17f4f76318b834425257c8ea297e415e12c68b4361f63e8ae92/rpds_py-0.27.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdfe4bb2f9fe7458b7453ad3c33e726d6d1c7c0a72960bcc23800d77384e42df", size = 371402, upload-time = "2025-08-27T12:15:51.561Z" }, { url = "https://files.pythonhosted.org/packages/af/7c/e16b959b316048b55585a697e94add55a4ae0d984434d279ea83442e460d/rpds_py-0.27.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fabb8fd848a5f75a2324e4a84501ee3a5e3c78d8603f83475441866e60b94a3", size = 354084, upload-time = "2025-08-27T12:15:53.219Z" }, { url = "https://files.pythonhosted.org/packages/de/c1/ade645f55de76799fdd08682d51ae6724cb46f318573f18be49b1e040428/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda8719d598f2f7f3e0f885cba8646644b55a187762bec091fa14a2b819746a9", size = 383090, upload-time = "2025-08-27T12:15:55.158Z" }, @@ -2900,22 +2243,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/2a/65880dfd0e13f7f13a775998f34703674a4554906167dce02daf7865b954/ruff-0.14.0-py3-none-win_arm64.whl", hash = "sha256:f42c9495f5c13ff841b1da4cb3c2a42075409592825dada7c5885c2c844ac730", size = 12565142, upload-time = "2025-10-07T18:21:53.577Z" }, ] +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + [[package]] name = "setproctitle" version = "1.3.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/48/fb401ec8c4953d519d05c87feca816ad668b8258448ff60579ac7a1c1386/setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b", size = 18079, upload-time = "2025-09-05T12:49:07.732Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a3/c2b0333c2716fb3b4c9a973dd113366ac51b4f8d56b500f4f8f704b4817a/setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7", size = 13099, upload-time = "2025-09-05T12:49:09.222Z" }, - { url = "https://files.pythonhosted.org/packages/0e/f8/17bda581c517678260e6541b600eeb67745f53596dc077174141ba2f6702/setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c", size = 31793, upload-time = "2025-09-05T12:49:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/27/d1/76a33ae80d4e788ecab9eb9b53db03e81cfc95367ec7e3fbf4989962fedd/setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3", size = 32779, upload-time = "2025-09-05T12:49:12.157Z" }, - { url = "https://files.pythonhosted.org/packages/59/27/1a07c38121967061564f5e0884414a5ab11a783260450172d4fc68c15621/setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f", size = 34578, upload-time = "2025-09-05T12:49:13.393Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d4/725e6353935962d8bb12cbf7e7abba1d0d738c7f6935f90239d8e1ccf913/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64", size = 32030, upload-time = "2025-09-05T12:49:15.362Z" }, - { url = "https://files.pythonhosted.org/packages/67/24/e4677ae8e1cb0d549ab558b12db10c175a889be0974c589c428fece5433e/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5", size = 33363, upload-time = "2025-09-05T12:49:16.829Z" }, - { url = "https://files.pythonhosted.org/packages/55/d4/69ce66e4373a48fdbb37489f3ded476bb393e27f514968c3a69a67343ae0/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381", size = 31508, upload-time = "2025-09-05T12:49:18.032Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5a/42c1ed0e9665d068146a68326529b5686a1881c8b9197c2664db4baf6aeb/setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c", size = 12558, upload-time = "2025-09-05T12:49:19.742Z" }, - { url = "https://files.pythonhosted.org/packages/dc/fe/dd206cc19a25561921456f6cb12b405635319299b6f366e0bebe872abc18/setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95", size = 13245, upload-time = "2025-09-05T12:49:21.023Z" }, { url = "https://files.pythonhosted.org/packages/04/cd/1b7ba5cad635510720ce19d7122154df96a2387d2a74217be552887c93e5/setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0", size = 18085, upload-time = "2025-09-05T12:49:22.183Z" }, { url = "https://files.pythonhosted.org/packages/8f/1a/b2da0a620490aae355f9d72072ac13e901a9fec809a6a24fc6493a8f3c35/setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4", size = 13097, upload-time = "2025-09-05T12:49:23.322Z" }, { url = "https://files.pythonhosted.org/packages/18/2e/bd03ff02432a181c1787f6fc2a678f53b7dacdd5ded69c318fe1619556e8/setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f", size = 32191, upload-time = "2025-09-05T12:49:24.567Z" }, @@ -2956,29 +2313,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" }, { url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" }, { url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" }, - { url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" }, - { url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" }, - { url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" }, - { url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" }, - { url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" }, - { url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" }, - { url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" }, - { url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" }, - { url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" }, - { url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" }, - { url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" }, - { url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" }, - { url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" }, - { url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" }, - { url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" }, - { url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" }, - { url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" }, - { url = "https://files.pythonhosted.org/packages/34/8a/aff5506ce89bc3168cb492b18ba45573158d528184e8a9759a05a09088a9/setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6", size = 12654, upload-time = "2025-09-05T12:51:17.141Z" }, - { url = "https://files.pythonhosted.org/packages/41/89/5b6f2faedd6ced3d3c085a5efbd91380fb1f61f4c12bc42acad37932f4e9/setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2", size = 14284, upload-time = "2025-09-05T12:51:18.393Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c0/4312fed3ca393a29589603fd48f17937b4ed0638b923bac75a728382e730/setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78", size = 13282, upload-time = "2025-09-05T12:51:19.703Z" }, { url = "https://files.pythonhosted.org/packages/c3/5b/5e1c117ac84e3cefcf8d7a7f6b2461795a87e20869da065a5c087149060b/setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1", size = 12587, upload-time = "2025-09-05T12:51:21.195Z" }, { url = "https://files.pythonhosted.org/packages/73/02/b9eadc226195dcfa90eed37afe56b5dd6fa2f0e5220ab8b7867b8862b926/setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65", size = 14286, upload-time = "2025-09-05T12:51:22.61Z" }, { url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" }, @@ -3078,8 +2412,7 @@ name = "textual-hires-canvas" version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "textual" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/f0/13f2a30ab7950cc3d5d5a2c893fbe3d40b4d129fd2cd30313260181578c4/textual_hires_canvas-0.14.0.tar.gz", hash = "sha256:0fa512492ddd2cd6c2a970a6beea58f5350f4cf25f40ad14ffd9fa86c6458769", size = 1251440, upload-time = "2026-01-10T22:16:56.708Z" } @@ -3092,8 +2425,7 @@ name = "textual-plot" version = "0.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "textual" }, { name = "textual-hires-canvas" }, ] @@ -3102,6 +2434,73 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/36/75eba496995e6f9a001cd601972eab753203167dfcccfbf1816e3959d28d/textual_plot-0.10.1-py3-none-any.whl", hash = "sha256:74ff3a8b2d84bd71b3a9abbac95139ff952f190e6bac60c7091911c63a1863ba", size = 50409, upload-time = "2026-02-01T13:27:41.013Z" }, ] +[[package]] +name = "tiktoken" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/e5/5f3cb2159769d0f4324c0e9e87f9de3c4b1cd45848a96b2eb3566ad5ca77/tiktoken-0.13.0.tar.gz", hash = "sha256:c9435714c3a84c2319499de9a300c0e604449dd0799ff246458b3bb6a7f433c1", size = 38986, upload-time = "2026-05-15T04:51:27.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/4c/1bc81f4cd53e827c4ee67ca951b5935724716049452d8dfa09b8b82372bb/tiktoken-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7bfe1849caa65d1e1d9871817170ec497bbb7984e182012e1bdce72f66608cdb", size = 1036353, upload-time = "2026-05-15T04:50:21.757Z" }, + { url = "https://files.pythonhosted.org/packages/75/91/10b9c7076bc02c246c853201fdbbe300a4b8c5ed7b84c25f7403f4e32655/tiktoken-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:91c180fe255bd5a86d8316210d2833a1d4d33d026cd86a67812f4773743c8d26", size = 984644, upload-time = "2026-05-15T04:50:23.256Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e4/fceae98015fab47fcd49b8bd7f46145bcd187a47e0add1e5378ed67ef980/tiktoken-0.13.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:059c8ecf554eb5b41e6e054ba467b871b03277d267dee7244380aca4359747d4", size = 1119261, upload-time = "2026-05-15T04:50:24.348Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/fe42ad00de01a8c4a49ad8649a2c8a316835a9cad5961b11d21eac0020a5/tiktoken-0.13.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:36217497eaffc158607a3b26f065300db2aefd43b115263f3b9688ce38146173", size = 1138253, upload-time = "2026-05-15T04:50:25.505Z" }, + { url = "https://files.pythonhosted.org/packages/03/c4/ccee1ecccca107e9a16efcecdeeb964c325305038554d466ece65b42338f/tiktoken-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:303f7d91b4fce3baddbcde05c139091d4caa5026ac7214c1dc7ff7a71ee429ff", size = 1185747, upload-time = "2026-05-15T04:50:27.02Z" }, + { url = "https://files.pythonhosted.org/packages/9d/03/cd0cba295522b91eb55c6b2704f1df895f8226cfe60ab10d4d51d0cc9e69/tiktoken-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5d48843bee149630eb735a99e1f4a85b47308d21868ea63163f6e87768d3cfed", size = 1241265, upload-time = "2026-05-15T04:50:28.815Z" }, + { url = "https://files.pythonhosted.org/packages/7e/25/a10efd564402d82c2ff50d12057353ace447aa8007deceaa48641f63d35c/tiktoken-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc1c44cd37b43fc46bae593129164f4f281e82ea116b57a85aa81bda57eafc94", size = 876509, upload-time = "2026-05-15T04:50:30.026Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/144bde4e01df66b34bb865557c7cd754ed08b036217ebd79c9db5e9048a9/tiktoken-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32ac870a806cfb260a02d0cb70426aef02e038297f8ad50df5040bb5af360791", size = 1034888, upload-time = "2026-05-15T04:50:31.579Z" }, + { url = "https://files.pythonhosted.org/packages/36/18/d4ac9d20956cdebca04841316660ed584c2fecdc2b81722a28bc7ad3b1e4/tiktoken-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d9980f11429ed2d737c463bb1fb78cf330caa026adf002f714aced7849a687b", size = 982970, upload-time = "2026-05-15T04:50:32.961Z" }, + { url = "https://files.pythonhosted.org/packages/74/ed/6bb8d05b9f731f749fee5c6f5ca63e981143c826a5985877330507bd13b7/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3f277ebea5edd7b8bf03c6f9431e1d67d517530115572b2dc1d465326e8f88c7", size = 1115741, upload-time = "2026-05-15T04:50:34.475Z" }, + { url = "https://files.pythonhosted.org/packages/34/de/2ca96b07a82d972b74fe4b46de055b79c904e45c7eab699354a0bfa697dc/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a116178fa7e1b4065bff05214360373a65cac22f965be7b3f73d00a0dbfe7649", size = 1136523, upload-time = "2026-05-15T04:50:35.782Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/9dafec002c2d4424378563cf4cf5c7fb93631d2a55013c8b87554ee4012c/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c397ddda233208345b01bd30f2fca79ff730e55731d0108a603f9bc57f6af3b", size = 1181954, upload-time = "2026-05-15T04:50:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d0/1f8578c45b2f24759b46f0b50d31878c63c73e6bf0f2227e10ec5c5408dc/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95097e4f89b06403976e498abf61a0ee73a7497e73fb599cb211d8197a054d91", size = 1240069, upload-time = "2026-05-15T04:50:38.221Z" }, + { url = "https://files.pythonhosted.org/packages/aa/90/28d7f154888610aa9237e541986beb62b479df29d193a5a0617dbb1514d0/tiktoken-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f2d16e7a7c783ad81f36e457d046d1f1c8af70b22aec8a13238efe531977c41", size = 874748, upload-time = "2026-05-15T04:50:39.587Z" }, + { url = "https://files.pythonhosted.org/packages/9c/83/b096c859c2a47c11731bf2f5885f4028b809dfe2396582883eed9cae372f/tiktoken-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5df5d1507bd245f1ccad4a074698240021239e455eb0bb4ced4e3d7181872154", size = 1034228, upload-time = "2026-05-15T04:50:40.988Z" }, + { url = "https://files.pythonhosted.org/packages/53/61/c68e123b6d753e3fc2751e9b18e732c9d8bf1e1926762e736eee935d931c/tiktoken-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8fe806a50664e83a6ffd56cbd1e4f5dcc6cd32a3e7538f70dc38b1a271384545", size = 982978, upload-time = "2026-05-15T04:50:42.195Z" }, + { url = "https://files.pythonhosted.org/packages/ef/8b/96cc178cc584e65d363134500f297790b06cd48cdeb1e8fcf7bbe60f4715/tiktoken-0.13.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:125bc05005e747f993a83dc67934249932d6e4209854452cd4c0b1d53fba3ba2", size = 1116355, upload-time = "2026-05-15T04:50:43.564Z" }, + { url = "https://files.pythonhosted.org/packages/86/f5/bab735d2c72ea55404b295d02d092644eb5f7cc6205e34d35eb9abfb9ab2/tiktoken-0.13.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5e6358911cab4adee6712da27d65573496a4f68cf8a2b5fca6a4ad10fc5748cf", size = 1135772, upload-time = "2026-05-15T04:50:44.782Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/6de04ebdf904edfaad87788011b3735087a0c9ea671b9027e1e4e965e8c8/tiktoken-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:975cbd78d085d75d26b59660e262736dcaed1e35f8f142cd6291025c01d25486", size = 1182415, upload-time = "2026-05-15T04:50:46.422Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9c/470a05f3b1caf038f44880e334d47ab674e0c80d514c66b375d14d5afa10/tiktoken-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ab9bc99fa020a4c283424590ecd7f3afd70c1c281cb3fa3192a6c3af9f9615", size = 1239879, upload-time = "2026-05-15T04:50:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/42/a6/c1936d16055436cb32e6c6128d68629622e00f4768562f55653752d34768/tiktoken-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:6b1615f0ff71953d19729ceb18865429c185b0a23c5353f1bbca34a394bf60f7", size = 874829, upload-time = "2026-05-15T04:50:49.202Z" }, + { url = "https://files.pythonhosted.org/packages/d6/07/acb5992c3772b5a36284f742cfb7a5895aa4471d1848ac31464ad50d7fdf/tiktoken-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6eb4a5bfbc6426938026b1a334e898ac53541360d62d8c689870160cc80abd67", size = 1033600, upload-time = "2026-05-15T04:50:50.4Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/742e9aec30f59b9f161f7ff7cd072e02ea836c9e1c0854a8076dfcd40d5c/tiktoken-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:43cee3e5400573b2046fbf092cc7a5bc30164f9e4c95ce20714da929df48737a", size = 982516, upload-time = "2026-05-15T04:50:52.03Z" }, + { url = "https://files.pythonhosted.org/packages/72/74/ca1541b053e7648254d2e4b42a253e1bb4359f2c91a0a8d49228c794e1a0/tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7de52e3f566d19b3b11bd37eea552c6c305ad74081f736882bd44d148ed4c48d", size = 1115518, upload-time = "2026-05-15T04:50:53.543Z" }, + { url = "https://files.pythonhosted.org/packages/46/e3/93825eaf5a4a504795b787e5d5dea07fbeb3dabf97aa7b450be8bde59c89/tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:51384448aa508e4df84c0f7c1dc3211c7f7b8096325660ee5fc82f3e11b381ce", size = 1136867, upload-time = "2026-05-15T04:50:55.191Z" }, + { url = "https://files.pythonhosted.org/packages/8c/46/002b68de6827091d5ae90b048f326e8aad8d953520950e5ce1508879414f/tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e28157350f7ebf35008dd8e9e0fdb621f976e4230c881099c85e8cf07eaa50e2", size = 1181826, upload-time = "2026-05-15T04:50:56.296Z" }, + { url = "https://files.pythonhosted.org/packages/db/c6/d393e3185a276505182f7abd93fe714f3c444a2be9180798fa052347504e/tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:165cf1820ea4a354985c2490a5205d4cc74661c934aca79dd0368232fff94e0f", size = 1239489, upload-time = "2026-05-15T04:50:57.918Z" }, + { url = "https://files.pythonhosted.org/packages/b7/4d/bc07d1f1635d4897a202acc0ae11c2886eaa7325c359ba4741b47bf8e225/tiktoken-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6c43a675ca14f6f2749ba7f12075d37456015a24b859f2517b9beb4ef30807ec", size = 873820, upload-time = "2026-05-15T04:50:59.528Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.23.0rc0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/dc/2ba78324f6c82284f8d3d03bba16e5771d075aa4d5e9b4ecbd87af846af2/tokenizers-0.23.0rc0.tar.gz", hash = "sha256:685c6d269444451a2cf276d3f2bf655f3d7094be20c6553e413ede86b03c637b", size = 361629, upload-time = "2026-04-24T05:37:42.81Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/b9/dda4065e0f4b62e0e5a625cbaeb928a611d847171e059066b3adfdb3866f/tokenizers-0.23.0rc0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bed69208ba6f74057e18e3c8ed73d62e681ff44f7be642ddeff747247c8a7a98", size = 3134709, upload-time = "2026-04-24T05:37:31.89Z" }, + { url = "https://files.pythonhosted.org/packages/fa/16/54bd9f9e5c3641fe3d6d0e5b1cee37c58cb7520d22752c2065fc5a83caff/tokenizers-0.23.0rc0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:951be943c0657d8fd12e104731165a56d995c87533cd7f70a9444ddd7afa7708", size = 3043651, upload-time = "2026-04-24T05:37:30.305Z" }, + { url = "https://files.pythonhosted.org/packages/86/11/54c1040ee93c8d74a364fbf4e17fd5d88e2eea940cbdba69d48d42a5a0c0/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704ffd50130f6c85aa76ad16c8218ff0f966b14c6e6cab7d0636e492e487ffa5", size = 3365683, upload-time = "2026-04-24T05:37:18.674Z" }, + { url = "https://files.pythonhosted.org/packages/14/79/c8a7bdfee971346119349dab62f9918de512a7e5a8177555eaa50d854e1f/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bcd2a49117ad88999bc5d18d05addf67ec28e69f53e609ab07733c1f96404583", size = 3228688, upload-time = "2026-04-24T05:37:21.137Z" }, + { url = "https://files.pythonhosted.org/packages/e1/32/a46ab1348d0b573dab69860eee601927b9934323e40f6f6018bb362a6013/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c52f927516521a3e1f6b6347f8bacedaf589eadd682e7ac87dac911d832c3a73", size = 3565137, upload-time = "2026-04-24T05:37:27.101Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f1/1a3b6a30388fe7d4b57b1ea7fcd6192341e479d65e50366ee0ba13d96d14/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d6add82746146a6e052295ac429949c2d8e723244aa97ffe30cfee6cd788e98", size = 3826198, upload-time = "2026-04-24T05:37:22.783Z" }, + { url = "https://files.pythonhosted.org/packages/a4/cb/161e52a424aa7ffb4097e8ce343d8dc2bdc42d590601032d4a9e6e5f7da5/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:564115d3d6d2560b0a6b833d7dc39330d2328262557fbbd5bb0a14fb09b2b6cb", size = 3449011, upload-time = "2026-04-24T05:37:25.324Z" }, + { url = "https://files.pythonhosted.org/packages/ff/31/0e4b77ca48b302a5db827584c9784f6cdbb35380c0dd1d7668712d477bb5/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82167864c62a3d83880ed23dea267aa5760e3fcf16fd73f94d413baf1968b211", size = 3337931, upload-time = "2026-04-24T05:37:28.723Z" }, + { url = "https://files.pythonhosted.org/packages/50/e4/939249edee0073417b2c9447fd3b06e90c283ef6df72f3124427edae1f96/tokenizers-0.23.0rc0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:85f29751c4490bfaefe7e0d4b18ef28cd6d5f84c411e88ca896832eb4f18dd69", size = 3416560, upload-time = "2026-04-24T05:37:24.091Z" }, + { url = "https://files.pythonhosted.org/packages/46/48/3a4bd2ba88af778e6fa6d03e271b2bc868f495745c8be91616781bf460d9/tokenizers-0.23.0rc0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f82b7578eaad0cbb72765d1fbaa7e7bc04c531337513a21f437b73e4617fcf46", size = 9810112, upload-time = "2026-04-24T05:37:33.679Z" }, + { url = "https://files.pythonhosted.org/packages/45/8a/70c9919aefc7f514d6e98fb9be379b2850ca071a841d88900278781a07b0/tokenizers-0.23.0rc0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e61dff90a4ad8dc7e7e124d67756d63cf3ae57e32f04fb35bb408af91f47ea70", size = 9631038, upload-time = "2026-04-24T05:37:36.207Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f6/c15a5514f50bf953b70d3d2b7fd1829aa327ba8c9c519c54623510d6f459/tokenizers-0.23.0rc0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:5835b35d9a4815c8a4097d4dbac79c39b780684ea417fa4a93b9165e12ff1383", size = 9959195, upload-time = "2026-04-24T05:37:38.194Z" }, + { url = "https://files.pythonhosted.org/packages/11/95/d1a6a0e6d6a9bc81b8124d83beb1fb1230310ee93938095f984a12fa336d/tokenizers-0.23.0rc0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:33ed7df57a040ffb6f0244639619632a06f4c287ed1e77b5e70febb58f9e9a8b", size = 10106242, upload-time = "2026-04-24T05:37:40.745Z" }, + { url = "https://files.pythonhosted.org/packages/78/c4/d9d587b9b32c9fca5ea901225d5c4c616802eb0082b17481d23808941641/tokenizers-0.23.0rc0-cp310-abi3-win32.whl", hash = "sha256:ab264a8ffdea05b5fd71a8bca6572762bde9b7aaadeba16dd25c7352a625fa71", size = 2523576, upload-time = "2026-04-24T05:37:47.173Z" }, + { url = "https://files.pythonhosted.org/packages/d8/9b/34b36f6a47fec0a160887da23f173aa8a1729fa425ee67944c9be27f58de/tokenizers-0.23.0rc0-cp310-abi3-win_amd64.whl", hash = "sha256:27fe690eeb35a3a7e52f47d96c2ce8ffc6f939cc51a4591be86d2c86b9881267", size = 2788929, upload-time = "2026-04-24T05:37:45.81Z" }, + { url = "https://files.pythonhosted.org/packages/35/ec/920d2b36ddddb5ce819a005d9650dc941935e534a27c48758c93388aaa5b/tokenizers-0.23.0rc0-cp310-abi3-win_arm64.whl", hash = "sha256:0b66c5eab2ddd26e59cfe6aa1945aa8b656ea0a9a715e24171c01b5ab1987630", size = 2655724, upload-time = "2026-04-24T05:37:44.108Z" }, +] + [[package]] name = "toml" version = "0.10.2" @@ -3141,25 +2540,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, - { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, - { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, - { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, - { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, - { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, - { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, - { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, - { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, - { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, ] +[[package]] +name = "tomli-w" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, +] + [[package]] name = "tqdm" version = "4.67.1" @@ -3172,6 +2564,27 @@ 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 = "transformers" +version = "4.57.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, +] + [[package]] name = "ty" version = "0.0.1a22" @@ -3288,45 +2701,73 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" }, ] +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, +] + [[package]] name = "verifiers" -version = "0.1.14" -source = { git = "https://github.com/PrimeIntellect-ai/verifiers.git?tag=v0.1.14#2fbd2b7fab0236cb039c4aa5afb25ad9c5f17134" } +version = "0.1.15.dev373" +source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "aiohttp" }, { name = "aiolimiter" }, { name = "anthropic" }, { name = "datasets" }, { name = "gepa" }, { name = "httpx" }, - { name = "jinja2" }, + { name = "loguru" }, { name = "math-verify" }, { name = "mcp" }, { name = "msgpack" }, - { name = "nest-asyncio" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "openai" }, { name = "openai-agents" }, + { name = "prime-pydantic-config", extra = ["toml"] }, { name = "prime-sandboxes" }, { name = "prime-tunnel" }, { name = "pydantic" }, { name = "pyzmq" }, - { name = "regex" }, + { name = "renderers" }, { name = "requests" }, { name = "rich" }, { name = "setproctitle" }, { name = "tenacity" }, - { name = "textual" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "tomli-w" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, - { name = "wget" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/a7/244c64fa3a7b31913cb82948bb2d6febf4bd6eabb57f0864cfb2657f8516/verifiers-0.1.15.dev373.tar.gz", hash = "sha256:051a8d4fd12cd676e68633fe5e0ca567da4f8f30f5908a48daf081162507a39d", size = 780290, upload-time = "2026-06-23T07:45:19.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/5d/aba59124e02672fbc51409cc7ab28a462b86a5df439ef898c077c9c9541d/verifiers-0.1.15.dev373-py3-none-any.whl", hash = "sha256:e2b65e35ba04ba97d13fcfb80212d8d0bdc6cec056677929b21c0994886bc0f7", size = 804378, upload-time = "2026-06-23T07:45:17.05Z" }, ] [[package]] @@ -3337,7 +2778,6 @@ dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a4/d5/b0ccd381d55c8f45d46f77df6ae59fbc23d19e901e2d523395598e5f4c93/virtualenv-20.35.3.tar.gz", hash = "sha256:4f1a845d131133bdff10590489610c98c168ff99dc75d6c96853801f7f67af44", size = 6002907, upload-time = "2025-10-10T21:23:33.178Z" } wheels = [ @@ -3345,10 +2785,13 @@ wheels = [ ] [[package]] -name = "wget" -version = "3.2" +name = "win32-setctime" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/6a/62e288da7bcda82b935ff0c6cfe542970f04e29c756b0e147251b2fb251f/wget-3.2.zip", hash = "sha256:35e630eca2aa50ce998b9b1a127bb26b30dfee573702782aa982f875e3f16061", size = 10857, upload-time = "2015-10-22T15:26:37.51Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] [[package]] name = "xxhash" @@ -3356,21 +2799,6 @@ version = "3.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, @@ -3431,36 +2859,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, - { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, - { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, - { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, - { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, - { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, - { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, - { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, - { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, - { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, - { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, - { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, - { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, - { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, - { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, - { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, - { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, - { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, - { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, - { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, @@ -3479,22 +2877,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, @@ -3559,38 +2941,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] From 518d3d9d3a0964efa50fbab24bb500b9faf3bf2c Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:00:05 +0200 Subject: [PATCH 03/19] fast-track Verifiers v1 dependencies --- pyproject.toml | 2 ++ uv.lock | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1e44b3b38..6e355923a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,9 @@ prime = false prime-sandboxes = false prime-tunnel = false prime-evals = false +prime-pydantic-config = false verifiers = false +renderers = false tasksets = false harnesses = false diff --git a/uv.lock b/uv.lock index 5308b7644..2ffeddfbd 100644 --- a/uv.lock +++ b/uv.lock @@ -13,11 +13,11 @@ exclude-newer-span = "P7D" [options.exclude-newer-package] verifiers = false +prime-pydantic-config = false tasksets = false -prime-pydantic-config = "2099-12-31T23:00:00Z" prime-tunnel = false prime-sandboxes = false -renderers = "2099-12-31T23:00:00Z" +renderers = false harnesses = false prime-evals = false prime = false From e126a2066785caf3a5eb666bc40f4cb7c6b0cab5 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:38:13 +0200 Subject: [PATCH 04/19] fix verifiers eval bridge edge cases --- .../prime/src/prime_cli/verifiers_bridge.py | 28 +++++++++++++++---- packages/prime/tests/test_eval_billing.py | 27 +++++++++++++++--- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 155821e3f..5f137700b 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -940,7 +940,10 @@ def run_eval_passthrough( ) raise typer.Exit(1) - if any(arg == "--resume" or arg.startswith("--resume=") for arg in passthrough_args): + legacy_eval = "--save-results" in passthrough_args + if not legacy_eval and any( + arg == "--resume" or arg.startswith("--resume=") for arg in passthrough_args + ): env = os.environ.copy() env["PRIME_API_KEY"] = config.api_key if config.team_id: @@ -950,7 +953,7 @@ def run_eval_passthrough( return # Hosted-eval sandboxes still emit the v0 CLI surface; v1 always saves results. - if "--save-results" in passthrough_args: + if legacy_eval: args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) configured_base_url = (config.inference_url or "").strip().rstrip("/") _validate_model(model, base_url, configured_base_url) @@ -1074,6 +1077,15 @@ def run_eval_passthrough( console.print("[red]Error:[/red] --client.headers must be a JSON object") raise typer.Exit(2) headers = {**headers, **parsed_headers} + header_index = next( + idx + for idx, arg in enumerate(args) + if arg == "--client.headers" or arg.startswith("--client.headers=") + ) + if args[header_index] == "--client.headers": + del args[header_index : header_index + 2] + else: + del args[header_index] headers["X-PI-Job-Id"] = job_id if resolved_env is not None and resolved_env.env_display_id: headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id @@ -1088,15 +1100,21 @@ def run_eval_passthrough( console.print("[dim]No rollout results produced.[/dim]") return results = convert_eval_results(load_results_jsonl(results_path)) - task_ids = {row["example_id"] for row in results if "example_id" in row} + rollout_counts: dict[object, int] = {} + for row in results: + if "example_id" in row: + example_id = row["example_id"] + rollout_counts[example_id] = rollout_counts.get(example_id, 0) + 1 rewards = [row["reward"] for row in results if isinstance(row.get("reward"), (int, float))] metadata = { "env": job_target, "model": model, - "num_examples": len(task_ids), - "rollouts_per_example": len(results) // len(task_ids) if task_ids else 0, + "num_examples": len(rollout_counts), "avg_reward": sum(rewards) / len(rewards) if rewards else 0.0, } + rollout_totals = set(rollout_counts.values()) + if len(rollout_totals) == 1: + metadata["rollouts_per_example"] = rollout_totals.pop() (output_dir / "metadata.json").write_text( json.dumps(metadata, indent=2) + "\n", encoding="utf-8" ) diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 88317c66e..6b27ad479 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -196,6 +196,7 @@ def __init__(self, timeout=None): assert "gpt-4.1-mini" in command assert "--api-base-url" not in command assert "--api-key-var" not in command + assert command.count("--client.headers") == 1 header_idx = len(command) - 1 - command[::-1].index("--client.headers") headers = json.loads(command[header_idx + 1]) assert headers["X-Test"] == "yes" @@ -228,6 +229,8 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): environment="legacy-env", passthrough_args=[ "--save-results", + "--resume", + "/tmp/legacy-results.jsonl", "--debug", "--num-examples", "1", @@ -240,6 +243,7 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): assert captured["command"][0] == "verifiers.cli.commands.eval" assert "--save-results" in captured["command"] + assert "--resume" in captured["command"] assert "--debug" in captured["command"] assert "--client.headers" not in captured["command"] @@ -575,7 +579,14 @@ def fake_run(command, env=None): assert (output_dir / "metadata.json").exists() -def test_eval_writes_v1_metadata(monkeypatch, tmp_path): +@pytest.mark.parametrize( + ("task_ids", "expected_rollouts"), + [ + ([0, 1], 1), + ([0, 0, 1], None), + ], +) +def test_eval_writes_v1_metadata(monkeypatch, tmp_path, task_ids, expected_rollouts): monkeypatch.chdir(tmp_path) monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() @@ -597,9 +608,14 @@ def test_eval_writes_v1_metadata(monkeypatch, tmp_path): def fake_run(command, env=None): output_dir = Path(command[command.index("--output-dir") + 1]) output_dir.mkdir(parents=True) + rewards = [1.0, 0.5, 0.75] rows = [ - {"task": {"idx": 0, "prompt": None}, "nodes": [], "rewards": {"correct": 1.0}}, - {"task": {"idx": 1, "prompt": None}, "nodes": [], "rewards": {"correct": 0.5}}, + { + "task": {"idx": task_id, "prompt": None}, + "nodes": [], + "rewards": {"correct": rewards[index]}, + } + for index, task_id in enumerate(task_ids) ] (output_dir / "results.jsonl").write_text( "".join(json.dumps(row) + "\n" for row in rows), encoding="utf-8" @@ -617,8 +633,11 @@ def fake_run(command, env=None): (metadata_path,) = tmp_path.glob("outputs/evals/*/*/metadata.json") metadata = json.loads(metadata_path.read_text()) assert metadata["num_examples"] == 2 - assert metadata["rollouts_per_example"] == 1 assert metadata["avg_reward"] == 0.75 + if expected_rollouts is None: + assert "rollouts_per_example" not in metadata + else: + assert metadata["rollouts_per_example"] == expected_rollouts def test_inference_client_uses_custom_timeout(monkeypatch): From d5884494c135ee0e6a244af239eba201f049fd52 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:45:08 +0200 Subject: [PATCH 05/19] fix v1 resume result upload --- .../prime/src/prime_cli/verifiers_bridge.py | 233 +++++++++--------- packages/prime/tests/test_eval_billing.py | 34 ++- 2 files changed, 155 insertions(+), 112 deletions(-) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 5f137700b..88c82444c 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -941,17 +941,6 @@ def run_eval_passthrough( raise typer.Exit(1) legacy_eval = "--save-results" in passthrough_args - if not legacy_eval and any( - arg == "--resume" or arg.startswith("--resume=") for arg in passthrough_args - ): - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id - command = plugin.build_module_command(plugin.eval_module, passthrough_args) - _run_command(command, env=env) - return - # Hosted-eval sandboxes still emit the v0 CLI surface; v1 always saves results. if legacy_eval: args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) @@ -990,110 +979,132 @@ def run_eval_passthrough( _print_environment_source_footer(resolved_env) return - target = environment.removeprefix("@") - is_config = _is_config_target(target) - args = list(passthrough_args) - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id - - config_data = toml.load(target) if is_config else {} - config_model = config_data.get("model") if isinstance(config_data, dict) else None - model = _parse_value_option(args, "--model", "-m") or config_model or DEFAULT_MODEL - if _parse_value_option(args, "--model", "-m") is None and not config_model: - args.extend(["--model", model]) - - configured_base_url = (config.inference_url or "").strip().rstrip("/") - config_client = config_data.get("client") if isinstance(config_data, dict) else None - config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None - base_url = ( - _parse_value_option(args, "--client.base-url", None) - or config_base_url - or configured_base_url - ) - if not base_url: - console.print( - "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." - ) - raise typer.Exit(1) - dry_run_arg = _parse_value_option(args, "--dry-run", None) - dry_run = config_data.get("dry_run") is True - if dry_run_arg is not None: - dry_run = dry_run_arg.lower() == "true" - if not dry_run: - _validate_model(model, base_url, configured_base_url) - _preflight_inference_billing(model, base_url, configured_base_url) - - env_dir_path = DEFAULT_ENV_DIR_PATH - run_target = target - upstream_slug: Optional[str] = None - env_name_for_upload: Optional[str] = None - resolved_env: Optional[ResolvedEnvironment] = None - config_envs: list[tuple[str, str]] = [] + resume_dir = _parse_value_option(passthrough_args, "--resume", None) + if resume_dir is not None: + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + command = plugin.build_module_command(plugin.eval_module, passthrough_args) + _run_command(command, env=env) - if is_config: - taskset = config_data.get("taskset", {}) - if isinstance(taskset, dict) and isinstance(taskset.get("id"), str): - config_envs = [(taskset["id"], env_dir_path)] - for env_ref, ref_env_dir in config_envs: - _prepare_single_environment(plugin, env_ref, ref_env_dir) - run_target = f"@{target}" + output_dir = Path(resume_dir) + saved_config = toml.load(output_dir / "config.toml") + model = saved_config["model"] + taskset_id = saved_config["taskset"]["id"] + job_target = _env_name_from_reference(taskset_id) + saved_headers = saved_config.get("client", {}).get("headers", {}) + job_id = saved_headers.get("X-PI-Job-Id") or _build_job_id(job_target, model) + display_id = saved_headers.get(INTERNAL_ENV_DISPLAY_HEADER) + upstream_slug = display_id if isinstance(display_id, str) and "/" in display_id else None + env_name_for_upload = job_target + resolved_env = None + is_config = False else: - resolved_env = _prepare_single_environment(plugin, target, env_dir_path) - run_target = resolved_env.env_name - upstream_slug = resolved_env.upstream_slug - env_name_for_upload = resolved_env.env_name - - job_target = env_name_for_upload - if job_target is None and config_envs: - job_target = _env_name_from_reference(config_envs[0][0]) - if job_target is None: - job_target = Path(target).stem - job_id = _build_job_id(job_target, model) - output_dir_arg = _parse_value_option(args, "--output-dir", "-o") - config_output_dir = config_data.get("output_dir") if isinstance(config_data, dict) else None - configured_output_dir = output_dir_arg or config_output_dir - output_dir = ( - Path(configured_output_dir) - if configured_output_dir - else Path("outputs", "evals", f"{job_target}--{model.replace('/', '--')}", job_id) - ) - if configured_output_dir is None: - args.extend(["--output-dir", str(output_dir)]) - - headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} - if not isinstance(headers, dict): - console.print("[red]Error:[/red] client.headers must be a table") - raise typer.Exit(2) - cli_headers = _parse_value_option(args, "--client.headers", None) - if cli_headers: - try: - parsed_headers = json.loads(cli_headers) - except json.JSONDecodeError as exc: - console.print("[red]Error:[/red] --client.headers must be valid JSON") - raise typer.Exit(2) from exc - if not isinstance(parsed_headers, dict): - console.print("[red]Error:[/red] --client.headers must be a JSON object") - raise typer.Exit(2) - headers = {**headers, **parsed_headers} - header_index = next( - idx - for idx, arg in enumerate(args) - if arg == "--client.headers" or arg.startswith("--client.headers=") + target = environment.removeprefix("@") + is_config = _is_config_target(target) + args = list(passthrough_args) + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + + config_data = toml.load(target) if is_config else {} + config_model = config_data.get("model") if isinstance(config_data, dict) else None + model = _parse_value_option(args, "--model", "-m") or config_model or DEFAULT_MODEL + if _parse_value_option(args, "--model", "-m") is None and not config_model: + args.extend(["--model", model]) + + configured_base_url = (config.inference_url or "").strip().rstrip("/") + config_client = config_data.get("client") if isinstance(config_data, dict) else None + config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None + base_url = ( + _parse_value_option(args, "--client.base-url", None) + or config_base_url + or configured_base_url ) - if args[header_index] == "--client.headers": - del args[header_index : header_index + 2] + if not base_url: + console.print( + "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." + ) + raise typer.Exit(1) + dry_run_arg = _parse_value_option(args, "--dry-run", None) + dry_run = config_data.get("dry_run") is True + if dry_run_arg is not None: + dry_run = dry_run_arg.lower() == "true" + if not dry_run: + _validate_model(model, base_url, configured_base_url) + _preflight_inference_billing(model, base_url, configured_base_url) + + env_dir_path = DEFAULT_ENV_DIR_PATH + run_target = target + upstream_slug: Optional[str] = None + env_name_for_upload: Optional[str] = None + resolved_env: Optional[ResolvedEnvironment] = None + config_envs: list[tuple[str, str]] = [] + + if is_config: + taskset = config_data.get("taskset", {}) + if isinstance(taskset, dict) and isinstance(taskset.get("id"), str): + config_envs = [(taskset["id"], env_dir_path)] + for env_ref, ref_env_dir in config_envs: + _prepare_single_environment(plugin, env_ref, ref_env_dir) + run_target = f"@{target}" else: - del args[header_index] - headers["X-PI-Job-Id"] = job_id - if resolved_env is not None and resolved_env.env_display_id: - headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id - args.extend(["--client.headers", json.dumps(headers)]) - - console.print(f"[dim]Eval job_id: {job_id}[/dim]") - command = plugin.build_module_command(plugin.eval_module, [run_target, *args]) - _run_command(command, env=env) + resolved_env = _prepare_single_environment(plugin, target, env_dir_path) + run_target = resolved_env.env_name + upstream_slug = resolved_env.upstream_slug + env_name_for_upload = resolved_env.env_name + + job_target = env_name_for_upload + if job_target is None and config_envs: + job_target = _env_name_from_reference(config_envs[0][0]) + if job_target is None: + job_target = Path(target).stem + job_id = _build_job_id(job_target, model) + output_dir_arg = _parse_value_option(args, "--output-dir", "-o") + config_output_dir = config_data.get("output_dir") if isinstance(config_data, dict) else None + configured_output_dir = output_dir_arg or config_output_dir + output_dir = ( + Path(configured_output_dir) + if configured_output_dir + else Path("outputs", "evals", f"{job_target}--{model.replace('/', '--')}", job_id) + ) + if configured_output_dir is None: + args.extend(["--output-dir", str(output_dir)]) + + headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} + if not isinstance(headers, dict): + console.print("[red]Error:[/red] client.headers must be a table") + raise typer.Exit(2) + cli_headers = _parse_value_option(args, "--client.headers", None) + if cli_headers: + try: + parsed_headers = json.loads(cli_headers) + except json.JSONDecodeError as exc: + console.print("[red]Error:[/red] --client.headers must be valid JSON") + raise typer.Exit(2) from exc + if not isinstance(parsed_headers, dict): + console.print("[red]Error:[/red] --client.headers must be a JSON object") + raise typer.Exit(2) + headers = {**headers, **parsed_headers} + header_index = next( + idx + for idx, arg in enumerate(args) + if arg == "--client.headers" or arg.startswith("--client.headers=") + ) + if args[header_index] == "--client.headers": + del args[header_index : header_index + 2] + else: + del args[header_index] + headers["X-PI-Job-Id"] = job_id + if resolved_env is not None and resolved_env.env_display_id: + headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id + args.extend(["--client.headers", json.dumps(headers)]) + + console.print(f"[dim]Eval job_id: {job_id}[/dim]") + command = plugin.build_module_command(plugin.eval_module, [run_target, *args]) + _run_command(command, env=env) results_path = output_dir / "results.jsonl" if not results_path.exists(): diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 6b27ad479..6a560c367 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -266,12 +266,33 @@ def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): "prime_cli.verifiers_bridge._run_command", lambda command, env=None: captured.update(command=command, env=env), ) + monkeypatch.setattr( + "prime_cli.verifiers_bridge.push_eval_results_to_hub", + lambda **kwargs: captured.update(upload=kwargs), + ) output_dir = tmp_path / "previous-run" + output_dir.mkdir() + (output_dir / "config.toml").write_text( + """model = "openai/gpt-4.1-mini" + +[taskset] +id = "wiki-search" + +[client.headers] +X-PI-Job-Id = "existing-job-id" +X-Prime-Eval-Env-Display = "primeintellect/wiki-search" +""", + encoding="utf-8", + ) + (output_dir / "results.jsonl").write_text( + json.dumps({"id": 0, "reward": 1.0}) + "\n", + encoding="utf-8", + ) run_eval_passthrough( environment=str(output_dir), passthrough_args=["--resume", str(output_dir)], - skip_upload=True, + skip_upload=False, env_path=None, ) @@ -281,6 +302,17 @@ def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): str(output_dir), ] assert captured["env"]["PRIME_API_KEY"] == "test-api-key" + assert captured["upload"] == { + "env_name": "wiki-search", + "model": "openai/gpt-4.1-mini", + "job_id": "existing-job-id", + "env_path": None, + "upstream_slug": "primeintellect/wiki-search", + "output_dir": output_dir, + } + metadata = json.loads((output_dir / "metadata.json").read_text()) + assert metadata["num_examples"] == 1 + assert metadata["rollouts_per_example"] == 1 def test_eval_run_missing_endpoint_registry_falls_back_to_configured_inference( From 3f9723e01154c307982eb4e6f5204a7ef304812c Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:50:34 +0200 Subject: [PATCH 06/19] handle verifiers legacy flags and env paths --- packages/prime/src/prime_cli/commands/evals.py | 2 +- .../prime/src/prime_cli/verifiers_bridge.py | 14 ++++++++++++-- packages/prime/tests/test_eval_billing.py | 18 ++++++++++++------ packages/prime/tests/test_hosted_eval.py | 4 ++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 441548f5f..0c21ac7e2 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -1508,7 +1508,7 @@ def run_eval_cmd( local_passthrough_args = list(passthrough_args) if not hosted: - legacy_eval = "--save-results" in local_passthrough_args + legacy_eval = any(arg in ("--save-results", "-s") for arg in local_passthrough_args) if sampling_args is not None and legacy_eval: local_passthrough_args.extend(["--sampling-args", sampling_args]) elif sampling_args is not None: diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 88c82444c..5a66716a2 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -940,7 +940,7 @@ def run_eval_passthrough( ) raise typer.Exit(1) - legacy_eval = "--save-results" in passthrough_args + legacy_eval = _has_flag(passthrough_args, "--save-results", "-s") # Hosted-eval sandboxes still emit the v0 CLI surface; v1 always saves results. if legacy_eval: args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) @@ -1036,7 +1036,17 @@ def run_eval_passthrough( _validate_model(model, base_url, configured_base_url) _preflight_inference_billing(model, base_url, configured_base_url) - env_dir_path = DEFAULT_ENV_DIR_PATH + env_dir_path = _env_dir_path_arg(args) + if _parse_value_option(args, "--env-dir-path", None) is not None: + env_dir_index = next( + idx + for idx, arg in enumerate(args) + if arg == "--env-dir-path" or arg.startswith("--env-dir-path=") + ) + if args[env_dir_index] == "--env-dir-path": + del args[env_dir_index : env_dir_index + 2] + else: + del args[env_dir_index] run_target = target upstream_slug: Optional[str] = None env_name_for_upload: Optional[str] = None diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 6a560c367..5ba69d96d 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -164,9 +164,10 @@ def __init__(self, timeout=None): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_single_environment", - lambda *_args, **_kwargs: ResolvedEnvironment( - original="goblin-questions", - env_name="goblin-questions", + lambda _plugin, env_name, env_dir: captured.update(prepared=(env_name, env_dir)) + or ResolvedEnvironment( + original=env_name, + env_name=env_name, install_mode="local", ), ) @@ -184,6 +185,8 @@ def __init__(self, timeout=None): "https://api.openai.com/v1", "--client.headers", '{"X-Test": "yes"}', + "--env-dir-path", + str(tmp_path / "custom-envs"), "-n", "1", ], @@ -196,15 +199,18 @@ def __init__(self, timeout=None): assert "gpt-4.1-mini" in command assert "--api-base-url" not in command assert "--api-key-var" not in command + assert "--env-dir-path" not in command assert command.count("--client.headers") == 1 header_idx = len(command) - 1 - command[::-1].index("--client.headers") headers = json.loads(command[header_idx + 1]) assert headers["X-Test"] == "yes" assert headers["X-PI-Job-Id"].startswith("goblin_questions_gpt_4.1_mini_") + assert captured["prepared"] == ("goblin-questions", str(tmp_path / "custom-envs")) assert captured["env"]["PRIME_API_KEY"] == "test-api-key" -def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): +@pytest.mark.parametrize("save_flag", ["--save-results", "-s"]) +def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch, save_flag): monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() ) @@ -228,7 +234,7 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): run_eval_passthrough( environment="legacy-env", passthrough_args=[ - "--save-results", + save_flag, "--resume", "/tmp/legacy-results.jsonl", "--debug", @@ -242,7 +248,7 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch): ) assert captured["command"][0] == "verifiers.cli.commands.eval" - assert "--save-results" in captured["command"] + assert save_flag in captured["command"] assert "--resume" in captured["command"] assert "--debug" in captured["command"] assert "--client.headers" not in captured["command"] diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index 43a3d7ae3..6c7ac1b52 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -1403,7 +1403,7 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa "eval", "run", "legacy-env", - "--save-results", + "-s", "--sampling-args", '{"temperature":0.2}', ], @@ -1414,7 +1414,7 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa assert captured == { "environment": "legacy-env", "passthrough_args": [ - "--save-results", + "-s", "--sampling-args", '{"temperature":0.2}', ], From a3d41abef67fd996421409650db95912ff22a518 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:51:22 +0200 Subject: [PATCH 07/19] forward configured v1 inference URL --- packages/prime/src/prime_cli/verifiers_bridge.py | 9 ++++----- packages/prime/tests/test_eval_billing.py | 5 +++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 5a66716a2..2f1fe5a6a 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -1018,16 +1018,15 @@ def run_eval_passthrough( configured_base_url = (config.inference_url or "").strip().rstrip("/") config_client = config_data.get("client") if isinstance(config_data, dict) else None config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None - base_url = ( - _parse_value_option(args, "--client.base-url", None) - or config_base_url - or configured_base_url - ) + cli_base_url = _parse_value_option(args, "--client.base-url", None) + base_url = cli_base_url or config_base_url or configured_base_url if not base_url: console.print( "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." ) raise typer.Exit(1) + if cli_base_url is None and not config_base_url: + args.extend(["--client.base-url", base_url]) dry_run_arg = _parse_value_option(args, "--dry-run", None) dry_run = config_data.get("dry_run") is True if dry_run_arg is not None: diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 5ba69d96d..a9fcc6060 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -643,7 +643,10 @@ def test_eval_writes_v1_metadata(monkeypatch, tmp_path, task_ids, expected_rollo ), ) + captured = {} + def fake_run(command, env=None): + captured["command"] = command output_dir = Path(command[command.index("--output-dir") + 1]) output_dir.mkdir(parents=True) rewards = [1.0, 0.5, 0.75] @@ -670,6 +673,8 @@ def fake_run(command, env=None): (metadata_path,) = tmp_path.glob("outputs/evals/*/*/metadata.json") metadata = json.loads(metadata_path.read_text()) + base_url_index = captured["command"].index("--client.base-url") + assert captured["command"][base_url_index + 1] == DummyConfig.inference_url assert metadata["num_examples"] == 2 assert metadata["avg_reward"] == 0.75 if expected_rollouts is None: From 7b9f7992324b3063c1b823fb388dbdb6736ddf70 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:34:43 +0200 Subject: [PATCH 08/19] Delegate local eval env resolution to verifiers, fix @ config passing - Pass `@ config.toml` to the v1 CLI as two tokens; the pinned prime-pydantic-config only reads a root config file in that form, so the single-token `@config.toml` failed with "Unrecognized arguments". - Local v1 evals no longer probe hub owners or install remote envs prime-side: references (bare names, org/name[@version]) pass through verbatim and verifiers resolves them (`ensure_installed`). Prime only pre-installs local ./environments checkouts and keeps platform metadata for the results upload. Hosted evals and the v0 --save-results path keep the existing resolution (v0 does not self-install). - Config peek accepts both `taskset.id` and the legacy top-level `id` (verifiers' EvalConfig.is_legacy rule), so v1-format configs run v0 envs through the legacy bridge. - Declare prime-pydantic-config[toml]>=0.3.0.dev86 directly, matching the verifiers constraint. --- packages/prime/pyproject.toml | 1 + .../prime/src/prime_cli/verifiers_bridge.py | 48 ++++++++++++++----- packages/prime/tests/test_eval_billing.py | 47 +++++++++--------- uv.lock | 2 + 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/packages/prime/pyproject.toml b/packages/prime/pyproject.toml index 69ae175f6..970f18bb9 100644 --- a/packages/prime/pyproject.toml +++ b/packages/prime/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "pyyaml>=6.0.0", "toml>=0.10.0", "tomli>=2.0.0", + "prime-pydantic-config[toml]>=0.3.0.dev86", ] keywords = ["cli", "gpu", "cloud", "compute"] classifiers = [ diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 2f1fe5a6a..57502e387 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -588,7 +588,9 @@ def _choose_remote_owner(env_name: str, candidates: list[tuple[str, str]]) -> tu console.print(f"[red]Invalid selection.[/red] Enter 1-{len(candidates)}.") -def _resolve_environment_reference(env_reference: str, env_dir_path: str) -> ResolvedEnvironment: +def _resolve_environment_reference( + env_reference: str, env_dir_path: str, probe_remote: bool = True +) -> ResolvedEnvironment: base_ref, version = _split_version(env_reference) if _is_slug_reference(base_ref): @@ -647,7 +649,7 @@ def _resolve_environment_reference(env_reference: str, env_dir_path: str) -> Res local_env_path=local_dir, ) - if config is None or client is None: + if not probe_remote or config is None or client is None: return ResolvedEnvironment( original=env_reference, env_name=env_name, @@ -770,6 +772,23 @@ def _prepare_single_environment( return resolved +def _prepare_v1_environment( + plugin: PrimeVerifiersPlugin, env_reference: str, env_dir_path: str +) -> ResolvedEnvironment: + """Prepare `env_reference` for the v1 CLI, which resolves references itself: hub ids + (`org/name[@version]`) install on demand, anything else must be importable. Prime only + pre-installs a local checkout and collects platform metadata for the results upload.""" + resolved = _resolve_environment_reference(env_reference, env_dir_path, probe_remote=False) + if resolved.install_mode == "local": + console.print(f"[dim]Using local environment '{resolved.env_name}'[/dim]") + if resolved.env_display_id: + console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") + _install_local_environment(plugin, resolved.env_name, env_dir_path) + elif resolved.install_mode == "remote": + console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") + return resolved + + def _env_name_from_reference(env_reference: str) -> str: base_ref, _version = _split_version(env_reference) return base_ref.rsplit("/", 1)[-1] @@ -1046,22 +1065,27 @@ def run_eval_passthrough( del args[env_dir_index : env_dir_index + 2] else: del args[env_dir_index] - run_target = target upstream_slug: Optional[str] = None env_name_for_upload: Optional[str] = None resolved_env: Optional[ResolvedEnvironment] = None config_envs: list[tuple[str, str]] = [] if is_config: - taskset = config_data.get("taskset", {}) - if isinstance(taskset, dict) and isinstance(taskset.get("id"), str): - config_envs = [(taskset["id"], env_dir_path)] - for env_ref, ref_env_dir in config_envs: - _prepare_single_environment(plugin, env_ref, ref_env_dir) - run_target = f"@{target}" + taskset = config_data.get("taskset") + env_ref = taskset.get("id") if isinstance(taskset, dict) else None + if not (isinstance(env_ref, str) and env_ref): + # v1's legacy field: a top-level `id` runs a v0 env through the bridge + env_ref = config_data.get("id") + if isinstance(env_ref, str) and env_ref: + config_envs = [(env_ref, env_dir_path)] + for config_env_ref, ref_env_dir in config_envs: + _prepare_v1_environment(plugin, config_env_ref, ref_env_dir) + # pydantic-config only reads a root config file as two tokens: `@ path` + run_args = ["@", target] else: - resolved_env = _prepare_single_environment(plugin, target, env_dir_path) - run_target = resolved_env.env_name + resolved_env = _prepare_v1_environment(plugin, target, env_dir_path) + # hub refs (org/name[@version]) pass through verbatim; verifiers installs them + run_args = [resolved_env.install_slug or resolved_env.env_name] upstream_slug = resolved_env.upstream_slug env_name_for_upload = resolved_env.env_name @@ -1112,7 +1136,7 @@ def run_eval_passthrough( args.extend(["--client.headers", json.dumps(headers)]) console.print(f"[dim]Eval job_id: {job_id}[/dim]") - command = plugin.build_module_command(plugin.eval_module, [run_target, *args]) + command = plugin.build_module_command(plugin.eval_module, [*run_args, *args]) _run_command(command, env=env) results_path = output_dir / "results.jsonl" diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index a9fcc6060..a0893af3f 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -126,7 +126,7 @@ def chat_completion(self, payload, stream=False): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), ) @@ -163,12 +163,14 @@ def __init__(self, timeout=None): captured = {} monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, env_name, env_dir: captured.update(prepared=(env_name, env_dir)) - or ResolvedEnvironment( - original=env_name, - env_name=env_name, - install_mode="local", + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda _plugin, env_name, env_dir: ( + captured.update(prepared=(env_name, env_dir)) + or ResolvedEnvironment( + original=env_name, + env_name=env_name, + install_mode="local", + ) ), ) monkeypatch.setattr( @@ -351,7 +353,7 @@ def chat_completion(self, payload, stream=False): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), ) @@ -380,13 +382,13 @@ def test_gepa_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch captured = {} monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, environment, env_dir_path: captured.update( - {"environment": environment, "env_dir_path": env_dir_path} - ) - or ResolvedEnvironment( - original=environment, - env_name=environment, - install_mode="local", + lambda _plugin, environment, env_dir_path: ( + captured.update({"environment": environment, "env_dir_path": env_dir_path}) + or ResolvedEnvironment( + original=environment, + env_name=environment, + install_mode="local", + ) ), ) monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda command, env=None: None) @@ -422,7 +424,7 @@ def chat_completion(self, payload, stream=False): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), ) @@ -459,7 +461,7 @@ def chat_completion(self, payload, stream=False): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *args, **kwargs: (_ for _ in ()).throw(typer.Exit(0)), ) @@ -508,7 +510,7 @@ def fake_prepare(_plugin, env_reference, env_dir_path): def fake_run_command(command, env=None): commands.append(command) - monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_single_environment", fake_prepare) + monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_v1_environment", fake_prepare) monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run_command) run_eval_passthrough( @@ -520,7 +522,8 @@ def fake_run_command(command, env=None): assert prepared == [("primeintellect/wordle", "./environments")] assert commands - assert commands[0][1] == f"@{config_path}" + # pydantic-config only accepts a root config file as two tokens: `@ path` + assert commands[0][1:3] == ["@", str(config_path)] header_idx = commands[0].index("--client.headers") headers = json.loads(commands[0][header_idx + 1]) assert headers["X-PI-Job-Id"].startswith("wordle_openai_gpt_4.1_mini_") @@ -542,7 +545,7 @@ def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_conf lambda *_args: (_ for _ in ()).throw(AssertionError("dry-run must not make API calls")), ) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda _plugin, environment, _env_dir: ResolvedEnvironment( original=environment, env_name=environment, @@ -583,7 +586,7 @@ def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): monkeypatch.setattr( "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None ) - monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_single_environment", lambda *_: None) + monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_v1_environment", lambda *_: None) output_dir = tmp_path / "configured-output" config_path = tmp_path / "eval.toml" @@ -637,7 +640,7 @@ def test_eval_writes_v1_metadata(monkeypatch, tmp_path, task_ids, expected_rollo ) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *_args: ResolvedEnvironment( original="wiki-search", env_name="wiki-search", install_mode="local" ), diff --git a/uv.lock b/uv.lock index 2ffeddfbd..372c1278b 100644 --- a/uv.lock +++ b/uv.lock @@ -1382,6 +1382,7 @@ dependencies = [ { name = "gitignore-parser" }, { name = "httpx" }, { name = "prime-evals" }, + { name = "prime-pydantic-config", extra = ["toml"] }, { name = "prime-sandboxes" }, { name = "prime-tunnel" }, { name = "pydantic" }, @@ -1410,6 +1411,7 @@ requires-dist = [ { name = "gitignore-parser", specifier = ">=0.1.13" }, { name = "httpx", specifier = ">=0.25.0" }, { name = "prime-evals", editable = "packages/prime-evals" }, + { name = "prime-pydantic-config", extras = ["toml"], specifier = ">=0.3.0.dev86" }, { name = "prime-sandboxes", editable = "packages/prime-sandboxes" }, { name = "prime-tunnel", editable = "packages/prime-tunnel" }, { name = "pydantic", specifier = ">=2.0.0" }, From f696288f9b3a67fc6170d6e7a9fa4b87c903e45b Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:03:14 +0200 Subject: [PATCH 09/19] Address review feedback on the v1 eval bridge - Resume: only reuse the X-Prime-Eval-Env-Display header as the upload slug when it has slug shape; display values like "name (local - ahead of org/name)" contain a slash but are not slugs. - Results conversion: use vf's WireTrace alias; split prompt/completion at the first assistant turn; only the final branch carries the trace reward (earlier branches have no per-step reward, matching v0). - Fail fast with a pointed message when an eval config is in the old v0 format (env_id / [[eval]]) instead of surfacing a v1 parse error. --- .../prime/src/prime_cli/utils/eval_push.py | 18 ++++++++++++------ .../prime/src/prime_cli/verifiers_bridge.py | 12 +++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/prime/src/prime_cli/utils/eval_push.py b/packages/prime/src/prime_cli/utils/eval_push.py index 2e8ab7e82..fac989783 100644 --- a/packages/prime/src/prime_cli/utils/eval_push.py +++ b/packages/prime/src/prime_cli/utils/eval_push.py @@ -71,10 +71,9 @@ def convert_eval_results(samples: list[dict]) -> list[dict]: continue if trace_type is None: - from verifiers.v1.task import WireTask - from verifiers.v1.trace import Trace + from verifiers.v1.trace import WireTrace - trace_type = Trace[WireTask] + trace_type = WireTrace trace_fields = trace_type.model_fields trace = trace_type.model_validate( {key: value for key, value in sample.items() if key in trace_fields} @@ -89,13 +88,20 @@ def convert_eval_results(samples: list[dict]) -> list[dict]: if branches else [] ) + # v0-style split: prompt = messages before the first assistant turn + first_assistant = next( + (i for i, m in enumerate(main_messages) if m.get("role") == "assistant"), + len(main_messages), + ) + # the trace reward belongs to the completed (final) branch; earlier branches + # carry no per-step reward, matching v0 samples trajectory = [ { "messages": [ message.model_dump(mode="json", exclude_none=True) for message in branch.messages ], - "reward": trace.reward, + "reward": trace.reward if branch is branches[-1] else None, "num_input_tokens": branch.prompt_len, "num_output_tokens": branch.completion_len, } @@ -112,8 +118,8 @@ def convert_eval_results(samples: list[dict]) -> list[dict]: "example_id": example_id, "rollout_number": rollout_counts[example_id], "task": task, - "prompt": [], - "completion": main_messages, + "prompt": main_messages[:first_assistant], + "completion": main_messages[first_assistant:], "answer": task.get("answer"), "reward": trace.reward, "timing": trace.timing.model_dump(mode="json", exclude_none=True), diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 57502e387..45845b02b 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -1015,7 +1015,9 @@ def run_eval_passthrough( saved_headers = saved_config.get("client", {}).get("headers", {}) job_id = saved_headers.get("X-PI-Job-Id") or _build_job_id(job_target, model) display_id = saved_headers.get(INTERNAL_ENV_DISPLAY_HEADER) - upstream_slug = display_id if isinstance(display_id, str) and "/" in display_id else None + # display values like "name (local - ahead of org/name)" carry a "/" but are not slugs + is_slug = isinstance(display_id, str) and "/" in display_id and " " not in display_id + upstream_slug = display_id if is_slug else None env_name_for_upload = job_target resolved_env = None is_config = False @@ -1029,6 +1031,14 @@ def run_eval_passthrough( env["PRIME_TEAM_ID"] = config.team_id config_data = toml.load(target) if is_config else {} + if isinstance(config_data, dict) and ("env_id" in config_data or "eval" in config_data): + console.print( + "[red]Error:[/red] this looks like a legacy (v0) eval config " + "(`env_id` / `\\[\\[eval]]`). Run it on the v0 evaluator with " + "[bold]--save-results[/bold], or convert it to a v1 config " + "(`\\[taskset] id` for a v1 env, top-level `id` for a v0 env)." + ) + raise typer.Exit(2) config_model = config_data.get("model") if isinstance(config_data, dict) else None model = _parse_value_option(args, "--model", "-m") or config_model or DEFAULT_MODEL if _parse_value_option(args, "--model", "-m") is None and not config_model: From 56c29ebd347f542e1bfcf507a7d9fef6709f4d3b Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:23:25 +0200 Subject: [PATCH 10/19] Mirror v1 semantics for bare --dry-run and guard legacy uploads - A bare --dry-run (no value or followed by another flag) now skips the inference preflight, matching the v1 parser's bool-flag semantics. - The --save-results path now skips the automatic upload when the local checkout is ahead of its tracked upstream, mirroring the v1 path, so unpublished local code is never attributed to the stale upstream env. --- .../prime/src/prime_cli/verifiers_bridge.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 45845b02b..13fe43f8f 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -988,6 +988,16 @@ def run_eval_passthrough( console.print("[dim]Skipped uploading evaluation results[/dim]") return + # mirror the v1 path: never upload results from an unpublished local checkout, + # or the hub helper would attribute them to the stale tracked upstream + if resolved_env.recommend_push: + _print_environment_source_footer(resolved_env) + console.print( + "[yellow]Evaluation completed. Automatic upload is skipped until the local " + "environment is published.[/yellow]" + ) + return + push_eval_results_to_hub( env_name=resolved_env.env_name, model=model, @@ -1056,10 +1066,15 @@ def run_eval_passthrough( raise typer.Exit(1) if cli_base_url is None and not config_base_url: args.extend(["--client.base-url", base_url]) - dry_run_arg = _parse_value_option(args, "--dry-run", None) + # mirror v1 bool-flag semantics: a bare --dry-run (no value, or followed by + # another flag) means true; only an explicit false-y literal disables it dry_run = config_data.get("dry_run") is True - if dry_run_arg is not None: - dry_run = dry_run_arg.lower() == "true" + for idx, arg in enumerate(args): + if arg == "--dry-run": + value = args[idx + 1].lower() if idx + 1 < len(args) else "" + dry_run = value not in ("false", "0") + elif arg.startswith("--dry-run="): + dry_run = arg.split("=", 1)[1].lower() not in ("false", "0") if not dry_run: _validate_model(model, base_url, configured_base_url) _preflight_inference_billing(model, base_url, configured_base_url) From bd55bbc26eadff4512e8e0ccd4efbbdee722a3e7 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Sat, 4 Jul 2026 16:51:37 +0200 Subject: [PATCH 11/19] feat: raw v1 hosted evals, frozen v0 surface on the v1 CLI, prime eval rename Hosted evals: - prime eval --hosted (top-level [taskset]) submits the platform's raw `environments` payload; published envs keep environment_ids - hosted CLI flags collapse to one explicit-fields parse (no double argparse) Sandbox / v0 compatibility (verifiers no longer ships the v0 evaluator): - the frozen v0 argv surface (--save-results marker) and transitional [[eval]] TOMLs (incl. the platform's group_size dialect) convert onto the v1 CLI via verifiers.v1.cli.eval.compat; v0 env ids ride the legacy auto-detect, hub-slug taskset ids are installed and pinned to local names - --disable-tui/--debug map to --rich false; --disable-tui stays in the help so the platform's TUI probe keeps matching Command surface: - prime eval / @ config.toml is the canonical command; bare and --help invocations show the eval help with subcommands appended; `prime eval run` remains a hidden alias for hosted-eval sandboxes --- packages/prime/src/prime_cli/commands/env.py | 6 +- .../prime/src/prime_cli/commands/evals.py | 549 +++++++------ .../prime/src/prime_cli/commands/inference.py | 2 +- packages/prime/src/prime_cli/lab_setup.py | 2 +- .../prime/src/prime_cli/utils/eval_push.py | 281 ++----- .../prime/src/prime_cli/utils/hosted_eval.py | 4 +- .../src/prime_cli/utils/verifiers_v0_cli.py | 325 ++++++++ .../prime/src/prime_cli/verifiers_bridge.py | 740 ++++++++++-------- .../prime/src/prime_cli/verifiers_plugin.py | 73 +- .../src/prime_lab_app/agent_widget_model.py | 2 +- .../prime/src/prime_lab_app/config_screen.py | 2 +- packages/prime/src/prime_lab_app/data.py | 2 +- packages/prime/tests/test_env_push_path.py | 2 +- packages/prime/tests/test_eval_billing.py | 103 ++- packages/prime/tests/test_eval_help.py | 15 +- packages/prime/tests/test_eval_push.py | 358 +-------- packages/prime/tests/test_hosted_eval.py | 96 +++ packages/prime/tests/test_lab_setup.py | 2 +- packages/prime/tests/test_lab_view.py | 11 +- packages/prime/tests/test_v0_compat.py | 193 +++++ packages/prime/tests/test_validate.py | 173 ++++ 21 files changed, 1644 insertions(+), 1297 deletions(-) create mode 100644 packages/prime/src/prime_cli/utils/verifiers_v0_cli.py create mode 100644 packages/prime/tests/test_v0_compat.py create mode 100644 packages/prime/tests/test_validate.py diff --git a/packages/prime/src/prime_cli/commands/env.py b/packages/prime/src/prime_cli/commands/env.py index d8a9efe1b..2fd883872 100644 --- a/packages/prime/src/prime_cli/commands/env.py +++ b/packages/prime/src/prime_cli/commands/env.py @@ -1688,7 +1688,7 @@ def init( console.print("[dim]Example: prime env init my-env --path ./environments[/dim]") raise typer.Exit(2) - plugin = load_verifiers_prime_plugin(console=console) + plugin = load_verifiers_prime_plugin() command = plugin.build_module_command(plugin.init_module, [name, *passthrough_args]) result = subprocess.run(command) if result.returncode != 0: @@ -1728,7 +1728,7 @@ def build( console.print("[dim]Example: prime env build openenv-echo --path ./environments[/dim]") raise typer.Exit(2) - plugin = load_verifiers_prime_plugin(console=console) + plugin = load_verifiers_prime_plugin() command = plugin.build_module_command(plugin.build_module, [env_id, *passthrough_args]) result = subprocess.run(command) if result.returncode != 0: @@ -2467,7 +2467,7 @@ def install( """ try: client = APIClient(require_auth=False) - plugin = load_verifiers_prime_plugin(console=console) + plugin = load_verifiers_prime_plugin() # Validate package manager if with_tool not in ["uv", "pip"]: diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 0c21ac7e2..9eb503523 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -1,12 +1,11 @@ -import argparse import inspect import json -import re import time from functools import wraps from pathlib import Path from typing import Any, Optional +import toml import typer from click.core import ParameterSource from prime_evals import EvalsAPIError, EvalsClient, InvalidEvaluationError @@ -25,7 +24,6 @@ ) from ..utils.display import get_eval_viewer_url from ..utils.env_metadata import find_environment_metadata -from ..utils.eval_push import convert_eval_results, load_results_jsonl from ..utils.hosted_eval import ( EvalStatus, HostedEvalConfig, @@ -40,8 +38,10 @@ _split_owner_and_name, is_help_request, print_eval_run_help, + print_validate_help, run_eval_passthrough, run_eval_view, + run_validate_passthrough, ) console = get_console() @@ -84,7 +84,7 @@ HOSTED_LOGS_RETRY_WAIT_SECONDS = 10 HOSTED_LOGS_STATUS_UPDATE_EVERY_POLLS = 6 EVAL_TABLE_MAX_TEXT_WIDTH = 30 -EVAL_RUN_EXAMPLE_COMMAND = "prime eval run harbor_v1 -n 1" +EVAL_RUN_EXAMPLE_COMMAND = "prime eval harbor_v1 -n 1" EVAL_HOSTED_LABEL = "HOSTED" EVAL_LOCAL_LABEL = "LOCAL" # Legacy verifiers config fields/flags are accepted through the parser only so @@ -174,6 +174,15 @@ def format_usage(self, ctx, formatter): "[OPTIONS] ENVIRONMENT [ARGS]... | COMMAND [ARGS]...", ) + def parse_args(self, ctx, args): + # `prime eval` IS the eval command: bare and `--help` invocations show its + # help (subcommands are appended there) instead of a bare command listing. + decision_args = [arg for arg in args if arg != "--plain"] + if not decision_args or decision_args[0] in ("--help", "-h"): + plain = ["--plain"] if "--plain" in args else [] + args = [*plain, self.default_cmd_name, "--help"] + return super().parse_args(ctx, args) + subcommands_app = PlainTyper() @@ -259,7 +268,7 @@ def _validate_json_object_field(merged: dict[str, Any], field_name: str) -> None def _coerce_hosted_headers(raw: dict[str, Any]) -> list[str] | None: - from verifiers.cli.commands.eval import build_extra_headers + from ..utils.verifiers_v0_cli import build_extra_headers try: normalized = build_extra_headers(raw) @@ -272,51 +281,44 @@ def _coerce_hosted_headers(raw: dict[str, Any]) -> list[str] | None: return [f"{name}: {value}" for name, value in normalized.items()] -def _parse_verifiers_eval_namespace( +def _parse_hosted_cli_fields( environment: str, passthrough_args: list[str], sampling_args: Optional[str] -) -> tuple[argparse.Namespace, set[str], dict[str, str]]: - from verifiers.cli.commands.eval import build_parser +) -> dict[str, Any]: + """The explicitly-passed hosted CLI flags as v0 fields, headers pre-coerced.""" + from ..utils.verifiers_v0_cli import build_parser, v0_argv_to_fields - argv = [environment, *passthrough_args] + argv = list(passthrough_args) if sampling_args is not None: argv.extend(["--sampling-args", sampling_args]) - - explicit_parser = build_parser() - option_names_by_dest = {} - for action in explicit_parser._actions: - if action.option_strings: - action.default = argparse.SUPPRESS - option_names_by_dest[action.dest] = next( - (option for option in action.option_strings if option.startswith("--")), - action.option_strings[0], - ) - try: - parsed = build_parser().parse_args(argv) - explicit = explicit_parser.parse_args(argv) + fields = v0_argv_to_fields(environment, argv) except SystemExit as exc: raise typer.Exit(exc.code) from exc + fields.pop("env_target") - provided_dests = {dest for dest, value in vars(explicit).items() if dest != "env_id_or_config"} - return parsed, provided_dests, option_names_by_dest - - -def _reject_unsupported_hosted_verifiers_args( - provided_dests: set[str], option_names_by_dest: dict[str, str] -) -> None: + option_names_by_dest = { + action.dest: next( + (option for option in action.option_strings if option.startswith("--")), + action.option_strings[0], + ) + for action in build_parser()._actions + if action.option_strings + } unsupported_flags = [ - option_name - for dest, option_name in option_names_by_dest.items() - if dest in provided_dests and dest not in HOSTED_SUPPORTED_VERIFIERS_FIELDS + option_names_by_dest[dest] + for dest in fields + if dest not in HOSTED_SUPPORTED_VERIFIERS_FIELDS ] - if not unsupported_flags: - return + if unsupported_flags: + console.print( + "[red]Error:[/red] hosted eval CLI does not support: " + + ", ".join(f"`{flag}`" for flag in unsupported_flags) + ) + raise typer.Exit(1) - console.print( - "[red]Error:[/red] hosted eval CLI does not support: " - + ", ".join(f"`{flag}`" for flag in unsupported_flags) - ) - raise typer.Exit(1) + if "header" in fields: + fields["headers"] = _coerce_hosted_headers({"header": fields.pop("header")}) + return fields def _reject_legacy_unsupported_hosted_flags(passthrough_args: list[str]) -> None: @@ -428,7 +430,7 @@ def _resolve_hosted_config_model(raw_config: dict[str, Any], config_path: Path) def _validate_single_hosted_eval_config( merged: dict[str, Any], config_path: Path ) -> dict[str, Any]: - from verifiers.cli.commands.eval import merge_sampling_args + from ..utils.verifiers_v0_cli import merge_sampling_args unsupported_fields = sorted( field_name for field_name in merged if field_name not in HOSTED_SUPPORTED_TOML_FIELDS @@ -486,6 +488,113 @@ def _validate_single_hosted_eval_config( return merged +_V1_HOSTED_ENV_KEYS = ( + "taskset", + "harness", + "pool", + "timeout", + "retries", + "sampling", + "max_turns", + "max_input_tokens", + "max_output_tokens", + "max_total_tokens", + "multiplex", + "args", +) +_V1_HOSTED_RUN_KEYS = { + "model", + "client", + "num_tasks", + "num_examples", + "num_rollouts", + "rollouts_per_example", + "group_size", + "max_concurrent", + "verbose", + "extra_env_kwargs", + "timeout_minutes", + "allow_sandbox_access", + "allow_instances_access", + "allow_tunnel_access", + "eval_name", +} + + +def _first_config_value(raw: dict[str, Any], *keys: str) -> Any: + for key in keys: + if raw.get(key) is not None: + return raw[key] + return None + + +def _load_v1_hosted_target(config_path: Path) -> Optional[dict[str, Any]]: + """Load a v1-native eval TOML (`[taskset]`, no `env_id`/`[[eval]]`) as a hosted target. + + Returns a target config carrying the raw `environment` payload the platform accepts + under `environments`, or None when the file is not a v1-native config.""" + try: + raw = toml.load(config_path) + except Exception as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(1) from exc + if "env_id" in raw or "eval" in raw or "ablation" in raw: + return None + + taskset = raw.get("taskset") + if not (isinstance(taskset, dict) and taskset.get("id")): + if raw.get("id"): + console.print( + "[red]Error:[/red] hosted evals for legacy (v0) environments need a " + "published environment: use `env_id` in the config, or pass the " + "environment name directly." + ) + raise typer.Exit(1) + return None + + unsupported = sorted( + key for key in raw if key not in _V1_HOSTED_RUN_KEYS and key not in _V1_HOSTED_ENV_KEYS + ) + if unsupported: + console.print( + "[red]Error:[/red] hosted v1 eval config does not support: " + + ", ".join(f"`{field}`" for field in unsupported) + ) + raise typer.Exit(1) + + client = raw.get("client") or {} + if not isinstance(client, dict): + console.print("[red]Error:[/red] `client` must be a table") + raise typer.Exit(1) + headers_map = client.get("headers") or {} + headers = [f"{key}: {value}" for key, value in headers_map.items()] or None + + environment = {key: raw[key] for key in _V1_HOSTED_ENV_KEYS if raw.get(key) is not None} + optional = { + "num_examples": _first_config_value(raw, "num_tasks", "num_examples"), + "rollouts_per_example": _first_config_value( + raw, "num_rollouts", "rollouts_per_example", "group_size" + ), + "timeout_minutes": raw.get("timeout_minutes"), + "allow_sandbox_access": raw.get("allow_sandbox_access"), + "allow_instances_access": raw.get("allow_instances_access"), + "allow_tunnel_access": raw.get("allow_tunnel_access"), + "max_concurrent": raw.get("max_concurrent"), + "verbose": raw.get("verbose"), + "headers": headers, + "extra_env_kwargs": raw.get("extra_env_kwargs"), + "api_base_url": client.get("base_url"), + "api_key_var": client.get("api_key_var"), + "eval_name": raw.get("eval_name"), + } + return { + "env_id": None, + "environment": environment, + "model": raw.get("model") or DEFAULT_MODEL, + **{key: value for key, value in optional.items() if value is not None}, + } + + def _load_hosted_eval_configs(config_path_str: str) -> list[dict[str, Any]]: from verifiers.utils.eval_utils import load_toml_config @@ -552,10 +661,13 @@ def _build_hosted_evaluation_payload(config: HostedEvalConfig) -> dict[str, Any] eval_config["api_key_var"] = config.api_key_var payload: dict[str, Any] = { - "environment_ids": [config.environment_id], "inference_model": config.inference_model, "eval_config": eval_config, } + if config.environment is not None: + payload["environments"] = [config.environment] + else: + payload["environment_ids"] = [config.environment_id] if config.name: payload["name"] = config.name @@ -914,91 +1026,6 @@ def get_samples( format_output(data, output) -def _load_eval_directory(directory: Path) -> dict: - with open(directory / "metadata.json") as f: - metadata = json.load(f) - - env_field = metadata.get("env_id") or metadata.get("env") - if not env_field or "model" not in metadata: - raise ValueError( - f"Missing required 'env_id' or 'model' field in {directory / 'metadata.json'}" - ) - - results = convert_eval_results(load_results_jsonl(directory / "results.jsonl")) - - avg_pattern = re.compile(r"^avg_(.+)$") - metrics = {} - metadata_copy = {} - for key, value in metadata.items(): - if match := avg_pattern.match(key): - metrics[match.group(1)] = value - else: - metadata_copy[key] = value - - return { - "eval_name": f"{env_field}-{metadata['model']}", - "model_name": metadata["model"], - "env": env_field, - "metrics": metrics, - "metadata": metadata_copy, - "results": results, - } - - -def _has_eval_files(directory: Path) -> bool: - return (directory / "metadata.json").exists() and (directory / "results.jsonl").exists() - - -def _validate_eval_path(path_str: str) -> Path: - """Validate and return the evaluation directory path.""" - path = Path(path_str) - - if path.is_file(): - # Auto-correct: if user passed metadata.json or results.jsonl, use parent directory - if path.name in ("metadata.json", "results.jsonl"): - parent = path.parent - if _has_eval_files(parent): - return parent - raise ValueError( - f"Directory '{parent}' must contain both metadata.json and results.jsonl" - ) - raise ValueError( - f"Expected a directory path, but got file: {path}\n" - f"Pass a directory containing metadata.json and results.jsonl" - ) - - if path.is_dir(): - if _has_eval_files(path): - return path - - has_metadata = (path / "metadata.json").exists() - has_results = (path / "results.jsonl").exists() - if has_metadata and not has_results: - raise ValueError(f"Directory '{path}' is missing results.jsonl") - elif has_results and not has_metadata: - raise ValueError(f"Directory '{path}' is missing metadata.json") - else: - raise ValueError(f"Directory '{path}' is missing both metadata.json and results.jsonl") - - raise FileNotFoundError(f"Path not found: {path}") - - -def _discover_eval_outputs() -> list[Path]: - outputs_dir = Path("outputs/evals") - if not outputs_dir.exists(): - return [] - - eval_dirs = [] - for env_dir in outputs_dir.iterdir(): - if not env_dir.is_dir(): - continue - for run_dir in env_dir.iterdir(): - if run_dir.is_dir() and _has_eval_files(run_dir): - eval_dirs.append(run_dir) - - return sorted(eval_dirs) - - def _resolve_eval_viewer_url(evaluation_id: str, response: Optional[dict[str, Any]] = None) -> str: viewer_url = response.get("viewer_url") if response else None if viewer_url: @@ -1053,8 +1080,16 @@ def _push_single_eval( is_public: bool = False, name: Optional[str] = None, ) -> str: - path = _validate_eval_path(config_path) - eval_data = _load_eval_directory(path) + from verifiers.v1.cli.output import read_upload_data, resolve_eval_artifact_dir + + path = resolve_eval_artifact_dir(config_path) + upload = read_upload_data(path) + if upload.invalid_results: + console.print( + f"[yellow]Warning: Skipped {len(upload.invalid_results)} invalid " + "lines in results.jsonl[/yellow]" + ) + eval_data = upload.as_dict() eval_name = name or eval_data["eval_name"] console.print(f"[blue]✓ Loaded eval data:[/blue] {path}") @@ -1221,7 +1256,8 @@ def push_eval( ) -> None: """Push evaluation data to Prime Evals. - The directory must contain metadata.json and results.jsonl files. + The directory must contain a native verifiers run (config.toml + results.jsonl) + or legacy metadata.json + results.jsonl files. \b Examples: @@ -1248,21 +1284,23 @@ def push_eval( console.print(" prime eval push outputs/evals/env--model/run-id --eval-id ") raise typer.Exit(1) + from verifiers.v1.cli.output import discover_eval_artifact_dirs, has_eval_artifacts + if config_path is None: - current_dir = Path(".") - if _has_eval_files(current_dir): + if has_eval_artifacts(Path(".")): result_eval_id = _push_single_eval(".", env_id, run_id, eval_id, is_public, name) if output == "json": console.print() output_data_as_json({"evaluation_id": result_eval_id}, console) return - eval_dirs = _discover_eval_outputs() + eval_dirs = discover_eval_artifact_dirs() if not eval_dirs: console.print("[red]Error:[/red] No evaluation outputs found") console.print( - "[yellow]Hint:[/yellow] Run from a directory with " - "metadata.json and results.jsonl, or from a directory containing outputs/evals/" + "[yellow]Hint:[/yellow] Run from a directory with eval artifacts " + "(config.toml/metadata.json + results.jsonl), or from a directory " + "containing outputs/" ) raise typer.Exit(1) @@ -1340,8 +1378,8 @@ def push_eval( app = PlainTyper( cls=DefaultGroup, help=( - "Run evaluations or manage results (list, get, push, samples).\n\n" - "By default, 'prime eval ' runs 'prime eval run '." + "Run an evaluation ('prime eval ') " + "or manage results (list, get, push, samples)." ), no_args_is_help=True, ) @@ -1385,8 +1423,53 @@ def stop_cmd( raise typer.Exit(1) from exc +@app.command( + "validate", + help="Run each task's `validate` hook (model-free, per-task setup check)", + no_args_is_help=True, + context_settings={ + "allow_extra_args": True, + "ignore_unknown_options": True, + "help_option_names": [], + }, +) +def validate_cmd( + ctx: typer.Context, + environment: Optional[str] = typer.Argument( + None, + help="Taskset name/slug or TOML config path", + ), +) -> None: + """Run verifiers' validate (per-task validation, no model) with prime environment resolution.""" + passthrough_args = list(ctx.args) + if environment == "@": + if not passthrough_args: + console.print("[red]Error:[/red] @ must be followed by a config path.") + raise typer.Exit(2) + environment = passthrough_args.pop(0) + + if is_help_request(environment or "", passthrough_args): + print_validate_help() + raise typer.Exit(0) + + if environment is None: + console.print("[red]Error:[/red] Missing argument 'ENVIRONMENT'.") + console.print("[dim]Example: prime eval validate gsm8k-v1 -n 5[/dim]") + raise typer.Exit(2) + + if environment.startswith("-"): + console.print("[red]Error:[/red] Environment/config must be the first argument.") + console.print("[dim]Example: prime eval validate gsm8k-v1 -n 5[/dim]") + raise typer.Exit(2) + + run_validate_passthrough(environment=environment, passthrough_args=passthrough_args) + + @app.command( "run", + # the spelled-out alias of `prime eval `; hosted-eval sandboxes + # still emit it, so it stays routable but out of the help. + hidden=True, help="Run an evaluation with API models (default provider = Prime Inference)", no_args_is_help=True, context_settings={ @@ -1537,78 +1620,32 @@ def run_eval_cmd( if hosted: _reject_legacy_unsupported_hosted_flags(passthrough_args) - parsed_verifiers_args, cli_overrides, option_names_by_dest = ( - _parse_verifiers_eval_namespace( - environment, - passthrough_args, - sampling_args, - ) - ) - _reject_unsupported_hosted_verifiers_args(cli_overrides, option_names_by_dest) - env_dir_path = ( - parsed_verifiers_args.env_dir_path if "env_dir_path" in cli_overrides else None - ) - - cli_headers = None - if "header" in cli_overrides: - cli_headers = _coerce_hosted_headers({"header": parsed_verifiers_args.header}) + cli_fields = _parse_hosted_cli_fields(environment, passthrough_args, sampling_args) + env_dir_path = cli_fields.get("env_dir_path") hosted_target_configs: list[dict[str, Any]] = [] if _is_config_target(environment): - hosted_target_configs = _load_hosted_eval_configs(environment) + v1_target = _load_v1_hosted_target(Path(environment)) + if v1_target is not None: + hosted_target_configs = [v1_target] + else: + hosted_target_configs = _load_hosted_eval_configs(environment) else: hosted_target_configs = [ - { - "env_id": environment, - "env_dir_path": env_dir_path, - "model": DEFAULT_MODEL, - "num_examples": HOSTED_RUN_DEFAULT_NUM_EXAMPLES, - "rollouts_per_example": HOSTED_RUN_DEFAULT_ROLLOUTS_PER_EXAMPLE, - "env_args": None, - "timeout_minutes": None, - "allow_sandbox_access": True, - "allow_instances_access": False, - "allow_tunnel_access": True, - "sampling_args": None, - "max_concurrent": None, - "max_retries": None, - "state_columns": None, - "independent_scoring": False, - "verbose": False, - "headers": None, - "extra_env_kwargs": None, - "api_client_type": None, - "api_base_url": None, - "api_key_var": None, - "eval_name": None, - } + {"env_id": environment, "env_dir_path": env_dir_path, "model": DEFAULT_MODEL} ] parsed_custom_secrets = _parse_string_map_option(custom_secrets, "--custom-secrets") effective_targets: list[dict[str, Any]] = [] for target_config in hosted_target_configs: + merged = {**target_config, **cli_fields} # explicit CLI flags win over config try: - default_num_examples = int( - target_config.get("num_examples", HOSTED_RUN_DEFAULT_NUM_EXAMPLES) - ) - default_rollouts_per_example = int( - target_config.get( - "rollouts_per_example", - HOSTED_RUN_DEFAULT_ROLLOUTS_PER_EXAMPLE, - ) - ) - num_examples = ( - parsed_verifiers_args.num_examples - if "num_examples" in cli_overrides - else default_num_examples - ) - rollouts_per_example = ( - parsed_verifiers_args.rollouts_per_example - if "rollouts_per_example" in cli_overrides - else default_rollouts_per_example + num_examples = int(merged.get("num_examples", HOSTED_RUN_DEFAULT_NUM_EXAMPLES)) + rollouts_per_example = int( + merged.get("rollouts_per_example", HOSTED_RUN_DEFAULT_ROLLOUTS_PER_EXAMPLE) ) - except ValueError as exc: + except (TypeError, ValueError) as exc: console.print( "[red]Error:[/red] --num-examples and --rollouts-per-example must be integers" ) @@ -1621,33 +1658,19 @@ def run_eval_cmd( ) raise typer.Exit(1) - explicit_sampling_args = "sampling_args" in cli_overrides - base_sampling_args_raw = ( - parsed_verifiers_args.sampling_args - if explicit_sampling_args - else target_config.get("sampling_args") - ) - if base_sampling_args_raw is None: - base_sampling_args = None - elif isinstance(base_sampling_args_raw, dict): - base_sampling_args = base_sampling_args_raw - else: + base_sampling_args = merged.get("sampling_args") + if base_sampling_args is not None and not isinstance(base_sampling_args, dict): console.print("[red]Error:[/red] `sampling_args` must be a JSON object") raise typer.Exit(1) - from verifiers.cli.commands.eval import merge_sampling_args + from ..utils.verifiers_v0_cli import merge_sampling_args effective_sampling_args = ( merge_sampling_args( base_sampling_args, - max_tokens=( - parsed_verifiers_args.max_tokens if "max_tokens" in cli_overrides else None - ), - temperature=( - parsed_verifiers_args.temperature - if "temperature" in cli_overrides - else None - ), - prefer_existing_keys=explicit_sampling_args, + max_tokens=cli_fields.get("max_tokens"), + temperature=cli_fields.get("temperature"), + # an explicit --sampling-args wins over --max-tokens/--temperature + prefer_existing_keys="sampling_args" in cli_fields, ) or None ) @@ -1655,89 +1678,38 @@ def run_eval_cmd( effective_targets.append( { "env_id": target_config["env_id"], + "environment": target_config.get("environment"), "env_dir_path": target_config.get("env_dir_path") or env_dir_path, - "model": ( - parsed_verifiers_args.model - if "model" in cli_overrides - else target_config["model"] - ), + "model": merged["model"], "num_examples": num_examples, "rollouts_per_example": rollouts_per_example, - "env_args": ( - parsed_verifiers_args.env_args - if "env_args" in cli_overrides - else target_config.get("env_args") - ), + "env_args": merged.get("env_args"), "timeout_minutes": ( timeout_minutes if timeout_minutes is not None else target_config.get("timeout_minutes") ), "allow_sandbox_access": ( - allow_sandbox_access - if allow_sandbox_access - else target_config.get("allow_sandbox_access", True) + allow_sandbox_access or target_config.get("allow_sandbox_access", True) ), "allow_instances_access": ( - allow_instances_access - if allow_instances_access - else target_config.get("allow_instances_access", False) + allow_instances_access or target_config.get("allow_instances_access", False) ), "allow_tunnel_access": ( - allow_tunnel_access - if allow_tunnel_access - else target_config.get("allow_tunnel_access", True) + allow_tunnel_access or target_config.get("allow_tunnel_access", True) ), "custom_secrets": parsed_custom_secrets, "sampling_args": effective_sampling_args, - "max_concurrent": ( - parsed_verifiers_args.max_concurrent - if "max_concurrent" in cli_overrides - else target_config.get("max_concurrent") - ), - "max_retries": ( - parsed_verifiers_args.max_retries - if "max_retries" in cli_overrides - else target_config.get("max_retries") - ), - "state_columns": ( - parsed_verifiers_args.state_columns - if "state_columns" in cli_overrides - else target_config.get("state_columns") - ), - "independent_scoring": ( - parsed_verifiers_args.independent_scoring - if "independent_scoring" in cli_overrides - else target_config.get("independent_scoring", False) - ), - "verbose": ( - parsed_verifiers_args.verbose - if "verbose" in cli_overrides - else target_config.get("verbose", False) - ), - "headers": ( - cli_headers if "header" in cli_overrides else target_config.get("headers") - ), - "extra_env_kwargs": ( - parsed_verifiers_args.extra_env_kwargs - if "extra_env_kwargs" in cli_overrides - else target_config.get("extra_env_kwargs") - ), - "api_client_type": ( - parsed_verifiers_args.api_client_type - if "api_client_type" in cli_overrides - else target_config.get("api_client_type") - ), - "api_base_url": ( - parsed_verifiers_args.api_base_url - if "api_base_url" in cli_overrides - else target_config.get("api_base_url") - ), - "api_key_var": ( - parsed_verifiers_args.api_key_var - if "api_key_var" in cli_overrides - else target_config.get("api_key_var") - ), + "max_concurrent": merged.get("max_concurrent"), + "max_retries": merged.get("max_retries"), + "state_columns": merged.get("state_columns"), + "independent_scoring": merged.get("independent_scoring", False), + "verbose": merged.get("verbose", False), + "headers": merged.get("headers"), + "extra_env_kwargs": merged.get("extra_env_kwargs"), + "api_client_type": merged.get("api_client_type"), + "api_base_url": merged.get("api_base_url"), + "api_key_var": merged.get("api_key_var"), "eval_name": eval_name or target_config.get("eval_name"), } ) @@ -1753,6 +1725,7 @@ def run_eval_cmd( for target in effective_targets: group_key = ( target["model"], + _freeze_json_value(target.get("environment")), target["num_examples"], target["rollouts_per_example"], _freeze_json_value(target.get("env_args")), @@ -1787,6 +1760,12 @@ def run_eval_cmd( for group_key in target_order: group = grouped_targets[group_key] for grouped_target in group["targets"]: + raw_environment = grouped_target.get("environment") + if raw_environment is not None: + # raw v1 configs need no published environment on the platform + group["platform_slugs"].append(raw_environment["taskset"]["id"]) + group["environment_ids"].append(None) + continue platform_slug, environment_id = _resolve_hosted_environment( grouped_target["env_id"], env_dir_path=grouped_target["env_dir_path"], @@ -1804,8 +1783,10 @@ def run_eval_cmd( for group_key in target_order: group = grouped_targets[group_key] target = group["target"] + raw_environment = target.get("environment") hosted_config = HostedEvalConfig( environment_id=group["environment_ids"][0], + environment=raw_environment, inference_model=target["model"], num_examples=target["num_examples"], rollouts_per_example=target["rollouts_per_example"], @@ -1830,7 +1811,7 @@ def run_eval_cmd( ) result = _create_hosted_evaluations( hosted_config, - environment_ids=group["environment_ids"], + environment_ids=None if raw_environment else group["environment_ids"], ) all_platform_slugs.extend(group["platform_slugs"]) all_evaluation_ids.extend(result.get("evaluation_ids") or [result["evaluation_id"]]) diff --git a/packages/prime/src/prime_cli/commands/inference.py b/packages/prime/src/prime_cli/commands/inference.py index 1442a1187..e842a67a9 100644 --- a/packages/prime/src/prime_cli/commands/inference.py +++ b/packages/prime/src/prime_cli/commands/inference.py @@ -18,7 +18,7 @@ app = PlainTyper( help="Run and manage Prime Inference\n\n" - "Use `prime eval run` for environment evals with Prime Inference.", + "Use `prime eval` for environment evals with Prime Inference.", no_args_is_help=True, ) console = get_console() diff --git a/packages/prime/src/prime_cli/lab_setup.py b/packages/prime/src/prime_cli/lab_setup.py index c0874d807..21b2a043f 100644 --- a/packages/prime/src/prime_cli/lab_setup.py +++ b/packages/prime/src/prime_cli/lab_setup.py @@ -1407,7 +1407,7 @@ def _post_setup_call_to_action(options: LabSetupOptions) -> Panel: command_table = Table.grid(padding=(0, 1)) command_table.add_row("[bold green]$[/bold green]", "prime env init my-env") command_table.add_row( - "[bold green]$[/bold green]", "prime eval run my-env -m openai/gpt-5.4-nano -n 5" + "[bold green]$[/bold green]", "prime eval my-env -m openai/gpt-5.4-nano -n 5" ) command_table.add_row("[bold green]$[/bold green]", "prime eval view") command_table.add_row("[bold green]$[/bold green]", "prime rl run configs/rl/qwen-3-5.toml") diff --git a/packages/prime/src/prime_cli/utils/eval_push.py b/packages/prime/src/prime_cli/utils/eval_push.py index fac989783..54153b756 100644 --- a/packages/prime/src/prime_cli/utils/eval_push.py +++ b/packages/prime/src/prime_cli/utils/eval_push.py @@ -1,7 +1,13 @@ -import json +"""Upload local eval runs to the Prime Evals Hub. + +Reading and converting the on-disk artifacts is verifiers' job +(`verifiers.v1.cli.output.read_upload_data`); this module owns the online part: +resolving the upstream environment and calling the Evals API. +""" + from datetime import datetime from pathlib import Path -from typing import Optional +from typing import TYPE_CHECKING, Optional from prime_evals import EvalsAPIError, EvalsClient @@ -11,230 +17,56 @@ from .env_metadata import find_environment_metadata from .plain import get_console -console = get_console() - - -def load_results_jsonl(path: Path) -> list[dict]: - """ - Load and parse a results.jsonl file, skipping invalid lines with warnings. - - Args: - path: Path to the results.jsonl file - - Returns: - List of valid dict samples from the file - """ - results = [] - skipped = [] - - with open(path, encoding="utf-8") as f: - for line_num, line in enumerate(f, start=1): - if not line.strip(): - continue - try: - sample = json.loads(line) - if not isinstance(sample, dict): - skipped.append((line_num, f"expected dict, got {type(sample).__name__}")) - continue - results.append(sample) - except json.JSONDecodeError: - skipped.append((line_num, "invalid JSON")) +if TYPE_CHECKING: + from verifiers.v1.cli.output import EvalUploadData - if skipped: - preview = [f"line {num}: {reason}" for num, reason in skipped[:5]] - suffix = ", ..." if len(skipped) > 5 else "" - console.print( - f"[yellow]Warning: Skipped {len(skipped)} invalid lines in results.jsonl " - f"({', '.join(preview)}{suffix})[/yellow]" - ) - - return results - - -def convert_eval_results(samples: list[dict]) -> list[dict]: - """Convert v1 traces to the sample schema while preserving legacy results.""" - trace_type = None - trace_fields = {} - rollout_counts: dict[int, int] = {} - converted = [] - - for sample in samples: - if not ( - isinstance(sample.get("nodes"), list) - and isinstance(sample.get("task"), dict) - and isinstance(sample.get("rewards"), dict) - ): - legacy_sample = dict(sample) - if "id" in legacy_sample and "example_id" not in legacy_sample: - legacy_sample["example_id"] = legacy_sample["id"] - converted.append(legacy_sample) - continue - - if trace_type is None: - from verifiers.v1.trace import WireTrace - - trace_type = WireTrace - trace_fields = trace_type.model_fields - trace = trace_type.model_validate( - {key: value for key, value in sample.items() if key in trace_fields} - ) - task = trace.task.model_dump(mode="json", exclude_none=True) - branches = trace.branches - main_messages = ( - [ - message.model_dump(mode="json", exclude_none=True) - for message in branches[-1].messages - ] - if branches - else [] - ) - # v0-style split: prompt = messages before the first assistant turn - first_assistant = next( - (i for i, m in enumerate(main_messages) if m.get("role") == "assistant"), - len(main_messages), - ) - # the trace reward belongs to the completed (final) branch; earlier branches - # carry no per-step reward, matching v0 samples - trajectory = [ - { - "messages": [ - message.model_dump(mode="json", exclude_none=True) - for message in branch.messages - ], - "reward": trace.reward if branch is branches[-1] else None, - "num_input_tokens": branch.prompt_len, - "num_output_tokens": branch.completion_len, - } - for branch in branches - ] - example_id = trace.task.idx - rollout_counts[example_id] = rollout_counts.get(example_id, 0) + 1 - info = dict(trace.info) - info.update({key: value for key, value in sample.items() if key not in trace_fields}) +console = get_console() - converted.append( - { - "sample_id": trace.id, - "example_id": example_id, - "rollout_number": rollout_counts[example_id], - "task": task, - "prompt": main_messages[:first_assistant], - "completion": main_messages[first_assistant:], - "answer": task.get("answer"), - "reward": trace.reward, - "timing": trace.timing.model_dump(mode="json", exclude_none=True), - "is_completed": trace.is_completed, - "is_truncated": trace.is_truncated, - "metrics": trace.metrics, - "error": ( - trace.error.model_dump(mode="json", exclude_none=True) if trace.error else None - ), - "stop_condition": trace.stop_condition, - "trajectory": trajectory, - "token_usage": ( - trace.usage.model_dump(mode="json", exclude_none=True) if trace.usage else None - ), - "num_steps": trace.num_turns, - "info": info or None, - } - ) - return converted +def find_latest_eval_output_dir(env_name: str, model: str) -> Path: + """The newest run directory in the legacy (v0) eval output layout.""" + module_name = env_name.replace("-", "_") + env_model_str = f"{env_name}--{model.replace('/', '--')}" + local_env_dir = Path("./environments") / module_name + base_evals_dir = ( + local_env_dir / "outputs" / "evals" / env_model_str + if local_env_dir.exists() + else Path("./outputs") / "evals" / env_model_str + ) + if not base_evals_dir.exists(): + raise FileNotFoundError(f"Evaluation output directory not found: {base_evals_dir}") + subdirs = [d for d in base_evals_dir.iterdir() if d.is_dir()] + if not subdirs: + raise FileNotFoundError(f"No evaluation results found in {base_evals_dir}") + return max(subdirs, key=lambda d: d.stat().st_mtime) def push_eval_results_to_hub( env_name: str, - model: str, job_id: str, - env_path: Optional[Path] = None, + upload: "EvalUploadData", upstream_slug: Optional[str] = None, - output_dir: Optional[Path] = None, + env_path: Optional[Path] = None, ) -> None: - """ - Push evaluation results to Prime Evals Hub after `prime eval run` completes. - - This function: - 1. Locates the most recent evaluation output directory - 2. Reads and parses metadata.json and results.jsonl - 3. Resolves environment ID (from metadata, upstream_slug, or by name) - 4. Converts results to Prime Evals API format - 5. Creates evaluation, pushes samples, and finalizes + """Create, populate, and finalize a platform evaluation from an `EvalUploadData` payload. - Args: - env_name: Environment name (e.g., "simpleqa") - model: Model identifier (e.g., "openai/gpt-4.1-mini") - job_id: Unique job ID for tracking - env_path: Optional path to the environment directory (defaults to current directory) - upstream_slug: Optional upstream environment slug (e.g., "primeintellect/wordle") - If provided, bypasses metadata file lookup + The upstream environment is `upstream_slug` when given, else looked up from the local + environment metadata; without either the upload is skipped with a hint. """ - # Step 1: Find the output directory - module_name = env_name.replace("-", "_") - if output_dir is None: - model_name = model.replace("/", "--") - env_model_str = f"{env_name}--{model_name}" - local_env_dir = Path("./environments") / module_name - base_evals_dir = ( - local_env_dir / "outputs" / "evals" / env_model_str - if local_env_dir.exists() - else Path("./outputs") / "evals" / env_model_str - ) - if not base_evals_dir.exists(): - raise FileNotFoundError(f"Evaluation output directory not found: {base_evals_dir}") - subdirs = [d for d in base_evals_dir.iterdir() if d.is_dir()] - if not subdirs: - raise FileNotFoundError(f"No evaluation results found in {base_evals_dir}") - output_dir = max(subdirs, key=lambda d: d.stat().st_mtime) - - metadata_path = output_dir / "metadata.json" - results_path = output_dir / "results.jsonl" - - if not metadata_path.exists(): - raise FileNotFoundError(f"metadata.json not found in {output_dir}") - if not results_path.exists(): - raise FileNotFoundError(f"results.jsonl not found in {output_dir}") - - with open(metadata_path, encoding="utf-8") as f: - metadata = json.load(f) - - results_samples = load_results_jsonl(results_path) - - resolved_env_slug = None + resolved_env_slug = upstream_slug resolved_env_id = None - - if upstream_slug: - resolved_env_slug = upstream_slug - resolved_env_id = None - else: - # Search for environment metadata in multiple possible locations + if not resolved_env_slug: hub_metadata = find_environment_metadata( env_name=env_name, env_path=env_path, - module_name=module_name, + module_name=env_name.replace("-", "_"), ) - if hub_metadata: - try: - # Prefer database ID if available (no resolution needed) - if hub_metadata.get("environment_id"): - resolved_env_id = hub_metadata.get("environment_id") - owner = hub_metadata.get("owner") - name = hub_metadata.get("name") - resolved_env_slug = f"{owner}/{name}" if owner and name else None - elif hub_metadata.get("owner") and hub_metadata.get("name"): - resolved_env_slug = f"{hub_metadata.get('owner')}/{hub_metadata.get('name')}" - resolved_env_id = None - else: - resolved_env_slug = None - resolved_env_id = None - except (KeyError, AttributeError) as e: - console.print( - f"[yellow]Warning: Could not parse environment metadata: {e}[/yellow]" - ) - resolved_env_slug = None - resolved_env_id = None + resolved_env_id = hub_metadata.get("environment_id") + owner, name = hub_metadata.get("owner"), hub_metadata.get("name") + if owner and name: + resolved_env_slug = f"{owner}/{name}" - # Require accurate upstream for evaluation tracking if not resolved_env_slug and not resolved_env_id: console.print( "[yellow]No upstream environment found. Evaluation results will not be " @@ -242,48 +74,35 @@ def push_eval_results_to_hub( "upstream, or use `--env-path` to specify the correct path to the " "environment.[/yellow]" ) - return None + return env_identifier = resolved_env_slug or resolved_env_id console.print(f"\n[blue]Uploading evaluation results, using upstream: {env_identifier}[/blue]") api_client = APIClient() - if resolved_env_id: environments = [{"id": resolved_env_id}] - elif resolved_env_slug: + else: try: owner, name = resolved_env_slug.split("/", 1) response = api_client.get(f"/environmentshub/{owner}/{name}/@latest") details = response.get("data", response) env_id = details.get("id") - if env_id: - environments = [{"id": env_id}] - else: - environments = [{"slug": resolved_env_slug}] + environments = [{"id": env_id}] if env_id else [{"slug": resolved_env_slug}] except Exception: environments = [{"slug": resolved_env_slug}] - else: - raise ValueError("No valid environment identifier found") - metrics = {k: v for k, v in metadata.items() if k.startswith("avg_")} - - eval_metadata = {"framework": "verifiers", "job_id": job_id, **metadata} - - converted_results = convert_eval_results(results_samples) - - eval_name = f"{env_name}--{model}--{datetime.now().strftime('%Y%m%d_%H%M%S')}" evals_client = EvalsClient(api_client) - + eval_name = f"{env_name}--{upload.model_name}--{datetime.now().strftime('%Y%m%d_%H%M%S')}" create_response = evals_client.create_evaluation( name=eval_name, environments=environments, - model_name=model, + model_name=upload.model_name, dataset=env_name, framework="verifiers", - task_type=metadata.get("task_type"), - metadata=eval_metadata, - metrics=metrics, + task_type=upload.metadata.get("task_type"), + metadata={"framework": "verifiers", "job_id": job_id, **upload.metadata}, + metrics=upload.metrics, is_public=False, # Private by default - only visible to the user who created it ) @@ -291,10 +110,10 @@ def push_eval_results_to_hub( if not eval_id: raise EvalsAPIError("Failed to get evaluation ID from create_evaluation response") - if converted_results: - evals_client.push_samples(eval_id, converted_results) + if upload.results: + evals_client.push_samples(eval_id, upload.results) - evals_client.finalize_evaluation(eval_id, metrics=metrics) + evals_client.finalize_evaluation(eval_id, metrics=upload.metrics) console.print("[green]✓ Successfully uploaded evaluation results[/green]") diff --git a/packages/prime/src/prime_cli/utils/hosted_eval.py b/packages/prime/src/prime_cli/utils/hosted_eval.py index f714c4bbc..8f502aedd 100644 --- a/packages/prime/src/prime_cli/utils/hosted_eval.py +++ b/packages/prime/src/prime_cli/utils/hosted_eval.py @@ -35,7 +35,7 @@ def color(self) -> str: @dataclass class HostedEvalConfig: - environment_id: str + environment_id: Optional[str] inference_model: str num_examples: int rollouts_per_example: int @@ -57,6 +57,8 @@ class HostedEvalConfig: api_client_type: Optional[str] = None api_base_url: Optional[str] = None api_key_var: Optional[str] = None + environment: Optional[dict[str, Any]] = None + """Raw v1 environment config sent as `environments` instead of `environment_ids`.""" @dataclass diff --git a/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py b/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py new file mode 100644 index 000000000..c0554c11f --- /dev/null +++ b/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py @@ -0,0 +1,325 @@ +"""The frozen v0 verifiers eval CLI argv surface, vendored for hosted evals. + +Hosted-eval sandboxes still emit the classic v0 `vf-eval` argv, so prime must parse +and validate that argument surface — to build hosted requests, and to convert local +runs onto the v1 CLI. Verifiers has removed the v0 CLI itself; the frozen parser +lives here (vendored from verifiers v0.1.15 `verifiers/scripts/eval.py`) while the +config-level compat helpers live in `verifiers.v1.cli.eval.compat`. +""" + +import argparse +import json +from typing import Any + +from verifiers.v1.cli.eval.compat import ( # noqa: F401 (re-exported for callers) + PROVIDER_CONFIGS, + build_extra_headers, + merge_sampling_args, +) + +DEFAULT_MODEL = "openai/gpt-4.1-mini" +DEFAULT_ENV_DIR_PATH = "./environments" +DEFAULT_ENDPOINTS_PATH = "./configs/endpoints.toml" +DEFAULT_NUM_EXAMPLES = 5 +DEFAULT_ROLLOUTS_PER_EXAMPLE = 3 +DEFAULT_MAX_CONCURRENT = 32 +DEFAULT_CLIENT_TYPE = "openai_chat_completions" +DEFAULT_PROVIDER = "prime" + + +def v0_argv_to_fields(environment: str, passthrough_args: list[str]) -> dict[str, Any]: + """Parse a frozen-surface argv into the explicitly-provided v0 fields. + + Returns only flags the caller actually passed (defaults suppressed), plus the + positional target under ``env_target``. Raises SystemExit on unknown flags, + exactly like the v0 CLI did. + """ + parser = build_parser() + for action in parser._actions: + if action.option_strings: + action.default = argparse.SUPPRESS + namespace = parser.parse_args([environment, *passthrough_args]) + fields = {k: v for k, v in vars(namespace).items() if k != "env_id_or_config"} + fields["env_target"] = namespace.env_id_or_config + return fields + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser() + parser.add_argument( + "env_id_or_config", + type=str, + default="gsm8k", + help="Environment module name or path to TOML config file.", + ) + parser.add_argument( + "--env-args", + "-a", + type=json.loads, + default={}, + help='Environment module arguments as JSON object (e.g., \'{"key": "value", "num": 42}\')', + ) + parser.add_argument( + "--env-dir-path", + type=str, + default=DEFAULT_ENV_DIR_PATH, + help="Path to environments directory", + ) + parser.add_argument( + "--provider", + "-p", + type=str, + default=None, + choices=list(PROVIDER_CONFIGS.keys()), + help=( + "Inference provider shorthand. Resolves --api-base-url and --api-key-var " + "automatically. Explicit --api-base-url / --api-key-var take precedence. " + "Overrides endpoint registry when model is in registry. " + "Falls back to 'prime' when model is not in registry." + ), + ) + parser.add_argument( + "--endpoints-path", + "-e", + type=str, + default=DEFAULT_ENDPOINTS_PATH, + help="Path to API endpoints TOML registry", + ) + parser.add_argument( + "--model", + "-m", + type=str, + default=DEFAULT_MODEL, + help="Name of model to evaluate", + ) + parser.add_argument( + "--api-client-type", + type=str, + default=None, + help=( + "Which client type to use ('openai_completions', 'openai_chat_completions', " + "'openai_chat_completions_token', 'openai_responses', 'renderer', " + "'anthropic_messages', 'nemorl_chat_completions')" + ), + choices=[ + "openai_completions", + "openai_chat_completions", + "openai_chat_completions_token", + "openai_responses", + "renderer", + "anthropic_messages", + "nemorl_chat_completions", + ], + ) + parser.add_argument( + "--api-key-var", + "-k", + type=str, + default=None, + help="Environment variable name for API key (overrides --provider)", + ) + parser.add_argument( + "--api-base-url", + "-b", + type=str, + default=None, + help="Base URL for API (overrides --provider)", + ) + parser.add_argument( + "--header", + action="append", + default=None, + help="Extra HTTP header to pass to inference API. 'Name: Value'. Repeatable.", + ) + parser.add_argument( + "--header-from-state", + action="append", + default=None, + help=( + "Per-request HTTP header whose value is read from the rollout state. " + "'Name: state_key' (e.g. 'X-Session-ID: trajectory_id'). Repeatable. " + "Defaults to X-Session-ID=trajectory_id if unset." + ), + ) + parser.add_argument( + "--num-examples", + "-n", + type=int, + default=None, + help="Number of examples to evaluate", + ) + parser.add_argument( + "--rollouts-per-example", + "-r", + type=int, + default=None, + help="Number of rollouts per example", + ) + parser.add_argument( + "--shuffle", + default=False, + action="store_true", + help="Shuffle the evaluation dataset before selecting examples", + ) + parser.add_argument( + "--shuffle-seed", + type=int, + default=None, + help="Seed for --shuffle. Defaults to 0 when --shuffle is enabled.", + ) + parser.add_argument( + "--max-concurrent", + "-c", + type=int, + default=DEFAULT_MAX_CONCURRENT, + help="Maximum number of concurrent requests", + ) + parser.add_argument( + "--max-tokens", + "-t", + type=int, + default=None, + help="Maximum number of tokens to generate (unset to use model default)", + ) + parser.add_argument( + "--temperature", "-T", type=float, default=None, help="Temperature for sampling" + ) + parser.add_argument( + "--sampling-args", + "-S", + type=json.loads, + default=None, + help=( + "Sampling arguments as JSON object. Keys here override --max-tokens/--temperature. " + 'Example: \'{"enable_thinking": false, "max_tokens": 256}\'' + ), + ) + parser.add_argument( + "--output-dir", + "-o", + type=str, + default=None, + help="Custom output directory for evaluation results and logs", + ) + parser.add_argument( + "--verbose", "-v", default=False, action="store_true", help="Verbose output" + ) + parser.add_argument( + "--no-interleave-scoring", + "-N", + default=False, + action="store_true", + help="Disable interleaving of scoring", + ) + parser.add_argument( + "--state-columns", + "-C", + type=lambda t: [s.strip() for s in t.split(",")], + default=[], + help="Comma-separated list of state columns to save (e.g., 'turn,timing')", + ) + parser.add_argument( + "--save-results", + "-s", + default=False, + action="store_true", + help="Save results to disk", + ) + parser.add_argument( + "--resume", + "-R", + nargs="?", + const=True, + default=None, + metavar="PATH", + help=( + "Resume from a previous run. Optionally provide a PATH; " + "if omitted, auto-detect the latest incomplete matching run." + ), + ) + parser.add_argument( + "--independent-scoring", + "-i", + default=False, + action="store_true", + help="Score each rollout individually instead of scoring by group", + ) + parser.add_argument( + "--save-to-hf-hub", + "-H", + default=False, + action="store_true", + help="Save dataset to Hugging Face Hub", + ) + parser.add_argument( + "--hf-hub-dataset-name", + "-D", + type=str, + default="", + help="Name of dataset to save to Hugging Face Hub", + ) + parser.add_argument( + "--extra-env-kwargs", + "-x", + type=json.loads, + default={}, + help=( + 'Extra environment as JSON object (e.g., \'{"key": "value", "num": 42}\'). ' + "Passed to environment constructor." + ), + ) + parser.add_argument( + "--timeout", + type=float, + default=None, + help=( + "Per-rollout wall-clock timeout in seconds. " + "Overrides timeout_seconds in --extra-env-kwargs." + ), + ) + parser.add_argument( + "--fullscreen", + "-f", + default=False, + action="store_true", + help="Use fullscreen (alternate-screen) mode for the Rich live evaluation display", + ) + parser.add_argument( + "--disable-tui", + "-d", + default=False, + action="store_true", + help="Disable Rich display; use normal logging and tqdm progress instead", + ) + parser.add_argument( + "--max-retries", + type=int, + default=3, + help="Max retries for transient infrastructure errors (default: 3)", + ) + parser.add_argument( + "--disable-env-server", + default=False, + action="store_true", + help="Do not start env servers when evaluating environments", + ) + parser.add_argument( + "--num-workers", + "-w", + default="auto", + help='Number of env server worker processes ("auto" = concurrency // 256, or an integer)', + ) + parser.add_argument( + "--abbreviated-summary", + "-A", + default=False, + action="store_true", + help="Abbreviated summary: show settings and stats only, skip example prompts/completions", + ) + parser.add_argument( + "--heartbeat-url", + type=str, + default=None, + help="Heartbeat URL for uptime monitoring", + ) + return parser diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 13fe43f8f..7e1a3330c 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -8,7 +8,7 @@ import subprocess import sys import uuid -from dataclasses import dataclass +from dataclasses import dataclass, replace from datetime import datetime from pathlib import Path from typing import Optional @@ -21,10 +21,10 @@ from .api.inference import InferenceAPIError, InferenceClient, InferencePaymentRequiredError from .client import APIClient, APIError -from .utils.env_metadata import find_environment_metadata, get_environment_metadata -from .utils.eval_push import convert_eval_results, load_results_jsonl, push_eval_results_to_hub +from .utils.env_metadata import get_environment_metadata +from .utils.eval_push import push_eval_results_to_hub from .utils.plain import get_console -from .verifiers_plugin import PrimeVerifiersPlugin, load_verifiers_prime_plugin +from .verifiers_plugin import load_verifiers_prime_plugin console = get_console() @@ -33,11 +33,10 @@ DEFAULT_ENDPOINTS_PATH = "./configs/endpoints.toml" PRIME_SLUG = "primeintellect" INTERNAL_ENV_DISPLAY_HEADER = "X-Prime-Eval-Env-Display" -LEGACY_EVAL_MODULE = "verifiers.cli.commands.eval" EVAL_PREFLIGHT_TIMEOUT = httpx.Timeout(connect=10.0, read=300.0, write=60.0, pool=60.0) MODULE_TO_PRIME_COMMAND = { - "verifiers.cli.commands.eval": "prime eval run", - "verifiers.v1.cli.eval.main": "prime eval run", + "verifiers.v1.cli.eval.main": "prime eval", + "verifiers.v1.cli.validate": "prime eval validate", "verifiers.cli.commands.gepa": "prime gepa run", "verifiers.cli.commands.init": "prime env init", "verifiers.v1.cli.init": "prime env init", @@ -50,6 +49,7 @@ MODULE_TO_CONSOLE_SCRIPT = { "verifiers.v1.cli.eval.main": "eval", "verifiers.v1.cli.init": "init", + "verifiers.v1.cli.validate": "validate", } @@ -121,13 +121,13 @@ def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> ) sanitized = re.sub(r"\bvf-[a-z0-9-]+\b", prime_command, sanitized) - if prime_command in {"prime eval run", "prime gepa run"}: + if prime_command in {"prime eval", "prime gepa run"}: sanitized = re.sub(r"\benv_id_or_config\b", "environment", sanitized) return sanitized.rstrip() + "\n" def _load_help_text(module_name: str, prime_command: str) -> str: - plugin = load_verifiers_prime_plugin(console=console) + plugin = load_verifiers_prime_plugin() command = plugin.build_module_command(module_name, ["--help"]) result = subprocess.run(command, capture_output=True, text=True) help_text = result.stdout @@ -142,6 +142,14 @@ def _load_help_text(module_name: str, prime_command: str) -> str: return _sanitize_help_text(help_text, module_name, prime_command) +def _load_module_help(module_name: str, prime_command: str) -> str: + try: + return _load_help_text(module_name, prime_command) + except Exception as exc: + console.print(f"[red]Failed to load help for {prime_command}:[/red] {exc}") + raise typer.Exit(1) from exc + + def _write_help(text: str) -> None: sys.stdout.write(text) sys.stdout.flush() @@ -150,9 +158,9 @@ def _write_help(text: str) -> None: def _append_eval_options(help_text: str) -> str: extra_lines = [ " --skip-upload Skip uploading evaluation results to the platform.", + " --disable-tui Disable the live display (alias for --rich false).", " --env-path PATH Explicit path for upstream environment metadata.", " --hosted Run the evaluation on the platform instead of locally.", - " stop EVAL_ID Cancel a running hosted evaluation.", " --poll-interval FLOAT Polling interval in seconds for hosted evaluations.", " --follow Follow hosted evaluation logs until completion.", " --timeout-minutes INTEGER Timeout in minutes for hosted evaluations.", @@ -163,6 +171,11 @@ def _append_eval_options(help_text: str) -> str: "Allow tunnel creation and management for hosted evaluations.", " --custom-secrets JSON Custom sandbox secrets for hosted evaluations.", " --eval-name TEXT Custom name for the hosted evaluation.", + "Subcommands:", + " list | get | samples | push Manage evaluation results.", + " logs EVAL_ID [-f] | stop EVAL_ID Follow or cancel hosted evaluations.", + " validate ENVIRONMENT Run each task's validate hook (model-free).", + " view Browse local runs in the lab TUI.", ] lines = help_text.rstrip("\n").splitlines() for extra_line in extra_lines: @@ -172,63 +185,28 @@ def _append_eval_options(help_text: str) -> str: def print_eval_run_help() -> None: - try: - help_text = _load_help_text( - load_verifiers_prime_plugin(console=console).eval_module, - "prime eval run", - ) - except Exception as exc: - console.print(f"[red]Failed to load help for prime eval run:[/red] {exc}") - raise typer.Exit(1) from exc - _write_help(_append_eval_options(help_text)) + plugin = load_verifiers_prime_plugin() + _write_help(_append_eval_options(_load_module_help(plugin.eval_module, "prime eval"))) def print_gepa_run_help() -> None: - try: - help_text = _load_help_text( - load_verifiers_prime_plugin(console=console).gepa_module, - "prime gepa run", - ) - except Exception as exc: - console.print(f"[red]Failed to load help for prime gepa run:[/red] {exc}") - raise typer.Exit(1) from exc - _write_help(help_text) + plugin = load_verifiers_prime_plugin() + _write_help(_load_module_help(plugin.gepa_module, "prime gepa run")) def print_env_init_help() -> None: - try: - help_text = _load_help_text( - load_verifiers_prime_plugin(console=console).init_module, - "prime env init", - ) - except Exception as exc: - console.print(f"[red]Failed to load help for prime env init:[/red] {exc}") - raise typer.Exit(1) from exc - _write_help(help_text) + plugin = load_verifiers_prime_plugin() + _write_help(_load_module_help(plugin.init_module, "prime env init")) def print_env_build_help() -> None: - try: - help_text = _load_help_text( - load_verifiers_prime_plugin(console=console).build_module, - "prime env build", - ) - except Exception as exc: - console.print(f"[red]Failed to load help for prime env build:[/red] {exc}") - raise typer.Exit(1) from exc - _write_help(help_text) + plugin = load_verifiers_prime_plugin() + _write_help(_load_module_help(plugin.build_module, "prime env build")) -def print_lab_setup_help() -> None: - try: - help_text = _load_help_text( - load_verifiers_prime_plugin(console=console).setup_module, - "prime lab setup", - ) - except Exception as exc: - console.print(f"[red]Failed to load help for prime lab setup:[/red] {exc}") - raise typer.Exit(1) from exc - _write_help(help_text) +def print_validate_help() -> None: + plugin = load_verifiers_prime_plugin() + _write_help(_load_module_help(plugin.validate_module, "prime eval validate")) def run_eval_view(env_dir: Optional[str], outputs_dir: Optional[str], limit: int = 50) -> None: @@ -266,6 +244,19 @@ def _has_flag(args: list[str], long_flag: str, short_flag: str) -> bool: return False +def _pop_value_option(args: list[str], long_flag: str) -> Optional[str]: + """Return the value of `long_flag` and remove flag + value from `args` in place.""" + for idx, arg in enumerate(args): + if arg == long_flag: + value = args[idx + 1] if idx + 1 < len(args) else None + del args[idx : idx + 2] + return value + if arg.startswith(f"{long_flag}="): + del args[idx] + return arg.split("=", 1)[1] + return None + + def _resolve_endpoint_alias(args: list[str], model: str) -> Optional[EndpointResolution]: endpoints_path = _parse_value_option(args, "--endpoints-path", "-e") or DEFAULT_ENDPOINTS_PATH try: @@ -348,13 +339,9 @@ def _split_owner_and_name(slug: str) -> Optional[tuple[str, str]]: def _environment_url_from_slug(slug: str) -> Optional[str]: - parts = _split_owner_and_name(slug) - if parts is None: + if _split_owner_and_name(slug) is None: return None - try: - frontend_url = Config().frontend_url.rstrip("/") - except Exception: - frontend_url = "https://app.primeintellect.ai" + frontend_url = Config().frontend_url.rstrip("/") return f"{frontend_url}/dashboard/environments/{slug}" @@ -476,15 +463,10 @@ def _fetch_remote_env_details( ) -> Optional[dict]: try: response = client.get(f"/environmentshub/{owner_slug}/{env_name}/@{version}") - details = response.get("data", response) if isinstance(response, dict) else None - if isinstance(details, dict): - return details - return {} - except APIError as exc: - message = str(exc).lower() - if "404" in message or "not found" in message: - return None + except APIError: return None + details = response.get("data", response) if isinstance(response, dict) else None + return details if isinstance(details, dict) else {} def _extract_remote_version_details(details: Optional[dict]) -> tuple[Optional[str], Optional[str]]: @@ -616,14 +598,9 @@ def _resolve_environment_reference( env_name = base_ref local_dir = _find_local_env_dir(env_name, env_dir_path) + # remote probing is optional context; a client that can't be built just degrades it try: - config = Config() - except Exception: - config = None - - client: Optional[APIClient] = None - try: - client = APIClient(require_auth=False) + client: Optional[APIClient] = APIClient(require_auth=False) except Exception: client = None @@ -649,7 +626,7 @@ def _resolve_environment_reference( local_env_path=local_dir, ) - if not probe_remote or config is None or client is None: + if not probe_remote or client is None: return ResolvedEnvironment( original=env_reference, env_name=env_name, @@ -662,7 +639,7 @@ def _resolve_environment_reference( if user_slug: owner_candidates.append(("personal", user_slug)) - team_slug = _fetch_active_team_slug(client, config.team_id) + team_slug = _fetch_active_team_slug(client, Config().team_id) if team_slug and team_slug != user_slug: owner_candidates.append(("team", team_slug)) @@ -713,14 +690,11 @@ def _run_command(command: list[str], env: Optional[dict[str, str]] = None) -> No raise typer.Exit(result.returncode) -def _install_local_environment( - plugin: PrimeVerifiersPlugin, env_name: str, env_dir_path: str -) -> None: - command = plugin.build_module_command( - plugin.install_module, - [env_name, "--path", env_dir_path], - ) - _run_command(command) +def _install_local_environment(env_path: Path) -> None: + """Make a local checkout importable for verifiers (which no longer installs anything).""" + from .commands.env import _uv_pip_command + + _run_command(_uv_pip_command("install", "-e", str(env_path))) def _is_installed(env_name: str, version: Optional[str]) -> bool: @@ -745,15 +719,13 @@ def _install_remote_environment(env_slug: str) -> None: raise typer.Exit(1) -def _prepare_single_environment( - plugin: PrimeVerifiersPlugin, env_reference: str, env_dir_path: str -) -> ResolvedEnvironment: +def _prepare_single_environment(env_reference: str, env_dir_path: str) -> ResolvedEnvironment: resolved = _resolve_environment_reference(env_reference, env_dir_path) if resolved.install_mode == "local": console.print(f"[dim]Using local environment '{resolved.env_name}'[/dim]") if resolved.env_display_id: console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") - _install_local_environment(plugin, resolved.env_name, env_dir_path) + _install_local_environment(resolved.local_env_path) return resolved if resolved.install_mode == "remote": if resolved.install_slug is None: @@ -772,20 +744,20 @@ def _prepare_single_environment( return resolved -def _prepare_v1_environment( - plugin: PrimeVerifiersPlugin, env_reference: str, env_dir_path: str -) -> ResolvedEnvironment: - """Prepare `env_reference` for the v1 CLI, which resolves references itself: hub ids - (`org/name[@version]`) install on demand, anything else must be importable. Prime only - pre-installs a local checkout and collects platform metadata for the results upload.""" +def _prepare_v1_environment(env_reference: str, env_dir_path: str) -> ResolvedEnvironment: + """Make `env_reference` importable before the v1 CLI runs: install a local checkout or a + hub slug (`org/name[@version]`). The v1 CLI only accepts locally importable ids, so hub + refs are installed here and run by bare name; bare names without a local checkout must + already be importable. Also collects platform metadata for the results upload.""" resolved = _resolve_environment_reference(env_reference, env_dir_path, probe_remote=False) if resolved.install_mode == "local": console.print(f"[dim]Using local environment '{resolved.env_name}'[/dim]") if resolved.env_display_id: console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") - _install_local_environment(plugin, resolved.env_name, env_dir_path) + _install_local_environment(resolved.local_env_path) elif resolved.install_mode == "remote": console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") + _install_remote_environment(resolved.install_slug or env_reference) return resolved @@ -942,6 +914,18 @@ def _print_environment_source_footer(resolved: Optional[ResolvedEnvironment]) -> ) +@dataclass(frozen=True) +class V1EvalRun: + """What the upload tail needs to know about a finished v1 eval subprocess.""" + + output_dir: Path + job_id: str + env_name: str + upstream_slug: Optional[str] = None + resolved_env: Optional[ResolvedEnvironment] = None + is_config: bool = False + + def run_eval_passthrough( environment: str, passthrough_args: list[str], @@ -949,9 +933,7 @@ def run_eval_passthrough( skip_upload: bool, env_path: Optional[str], ) -> None: - plugin = load_verifiers_prime_plugin(console=console) config = Config() - if not config.api_key: console.print( "[red]No API key configured.[/red] " @@ -959,288 +941,368 @@ def run_eval_passthrough( ) raise typer.Exit(1) - legacy_eval = _has_flag(passthrough_args, "--save-results", "-s") - # Hosted-eval sandboxes still emit the v0 CLI surface; v1 always saves results. - if legacy_eval: - args, env, model, base_url = _add_default_inference_and_key_args(passthrough_args, config) - configured_base_url = (config.inference_url or "").strip().rstrip("/") - _validate_model(model, base_url, configured_base_url) - _preflight_inference_billing(model, base_url, configured_base_url) + args = list(passthrough_args) + tui_disabled = _pop_tui_flags(args) - env_dir_path = _env_dir_path_arg(args) - resolved_env = _prepare_single_environment(plugin, environment, env_dir_path) - if resolved_env.env_display_id: - args.extend( - ["--header", f"{INTERNAL_ENV_DISPLAY_HEADER}: {resolved_env.env_display_id}"] - ) + # Hosted-eval sandboxes still emit the frozen v0 CLI surface (marked by + # --save-results); convert it onto the v1 CLI, which always saves results. + if _has_flag(args, "--save-results", "-s"): + run = _run_converted_v0_eval(environment, args, config, tui_disabled=tui_disabled) + else: + resume_dir = _parse_value_option(args, "--resume", None) + if resume_dir is not None: + run = _resume_v1_eval(resume_dir, args, config) + else: + run = _run_v1_eval(environment, args, config, tui_disabled=tui_disabled) + _upload_v1_results(run, skip_upload=skip_upload, env_path=env_path) - job_id = _build_job_id(resolved_env.env_name, model) - args.extend(["--header", f"X-PI-Job-Id: {job_id}"]) - if config.team_id: - args.extend(["--header", f"X-Prime-Team-ID: {config.team_id}"]) - console.print(f"[dim]Eval job_id: {job_id}[/dim]") - command = plugin.build_module_command(LEGACY_EVAL_MODULE, [resolved_env.env_name, *args]) - _run_command(command, env=env) +def run_validate_passthrough(environment: str, passthrough_args: list[str]) -> None: + """Run verifiers' `validate` (each task's `validate` hook, model-free) with prime's + environment resolution and auth env vars. Validate is fire-and-forget — nothing is + written to disk or uploaded, so there is no model, output-dir, resume, or dry-run path.""" + config = Config() + if not config.api_key: + console.print( + "[red]No API key configured.[/red] " + "Run [bold]prime login[/bold] or [bold]prime config set-api-key[/bold]." + ) + raise typer.Exit(1) - if skip_upload: - _print_environment_source_footer(resolved_env) - console.print("[dim]Skipped uploading evaluation results[/dim]") - return + target = environment.removeprefix("@") + is_config = _is_config_target(target) + args = list(passthrough_args) + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id - # mirror the v1 path: never upload results from an unpublished local checkout, - # or the hub helper would attribute them to the stale tracked upstream - if resolved_env.recommend_push: - _print_environment_source_footer(resolved_env) - console.print( - "[yellow]Evaluation completed. Automatic upload is skipped until the local " - "environment is published.[/yellow]" - ) - return + # prime-only option: verifiers must not see it + env_dir_path = _pop_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH - push_eval_results_to_hub( - env_name=resolved_env.env_name, - model=model, - job_id=job_id, - env_path=Path(env_path) if env_path else None, - upstream_slug=resolved_env.upstream_slug, - ) + if is_config: + # pydantic-config reads a root config file as two tokens: `@ path` + run_args = ["@", target] + else: + resolved_env = _prepare_v1_environment(target, env_dir_path) + # the v1 CLI accepts only locally importable ids; hub refs were installed above + run_args = [resolved_env.env_name] _print_environment_source_footer(resolved_env) - return - resume_dir = _parse_value_option(passthrough_args, "--resume", None) - if resume_dir is not None: - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id - command = plugin.build_module_command(plugin.eval_module, passthrough_args) - _run_command(command, env=env) - - output_dir = Path(resume_dir) - saved_config = toml.load(output_dir / "config.toml") - model = saved_config["model"] - taskset_id = saved_config["taskset"]["id"] - job_target = _env_name_from_reference(taskset_id) - saved_headers = saved_config.get("client", {}).get("headers", {}) - job_id = saved_headers.get("X-PI-Job-Id") or _build_job_id(job_target, model) - display_id = saved_headers.get(INTERNAL_ENV_DISPLAY_HEADER) - # display values like "name (local - ahead of org/name)" carry a "/" but are not slugs - is_slug = isinstance(display_id, str) and "/" in display_id and " " not in display_id - upstream_slug = display_id if is_slug else None - env_name_for_upload = job_target - resolved_env = None - is_config = False + plugin = load_verifiers_prime_plugin() + _run_command(plugin.build_module_command(plugin.validate_module, [*run_args, *args]), env=env) + + +def _pop_tui_flags(args: list[str]) -> bool: + """Remove the v0 TUI flags hosted-eval scripts append; v1 maps them to --rich false.""" + found = False + for flag in ("--disable-tui", "--debug"): + while flag in args: + args.remove(flag) + found = True + return found + + +def _load_transitional_fields(config_path: Path) -> dict: + from verifiers.v1.cli.eval.compat import transitional_config_to_fields + + try: + return transitional_config_to_fields(config_path) + except ValueError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + + +def _write_converted_v1_config( + fields: dict, *, tui_disabled: bool +) -> tuple[Path, ResolvedEnvironment]: + """Turn flattened v0 fields into a v1 config file with a locally importable env id.""" + from verifiers.v1.cli.eval.compat import ( + build_v1_eval_config, + write_converted_eval_config, + ) + + env_dir_path = str(fields.pop("env_dir_path", None) or DEFAULT_ENV_DIR_PATH) + taskset = fields.get("taskset") + taskset_id = taskset.get("id") if isinstance(taskset, dict) else None + env_ref = taskset_id or fields.get("id") + if not (isinstance(env_ref, str) and env_ref): + console.print("[red]Error:[/red] eval config requires an env_id or taskset.id") + raise typer.Exit(2) + + # install hub refs and pin the locally importable name into the config + resolved = _prepare_v1_environment(env_ref, env_dir_path) + if taskset_id: + fields["taskset"] = {**taskset, "id": resolved.env_name} else: - target = environment.removeprefix("@") - is_config = _is_config_target(target) - args = list(passthrough_args) - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id + fields["id"] = resolved.env_name - config_data = toml.load(target) if is_config else {} - if isinstance(config_data, dict) and ("env_id" in config_data or "eval" in config_data): - console.print( - "[red]Error:[/red] this looks like a legacy (v0) eval config " - "(`env_id` / `\\[\\[eval]]`). Run it on the v0 evaluator with " - "[bold]--save-results[/bold], or convert it to a v1 config " - "(`\\[taskset] id` for a v1 env, top-level `id` for a v0 env)." - ) - raise typer.Exit(2) - config_model = config_data.get("model") if isinstance(config_data, dict) else None - model = _parse_value_option(args, "--model", "-m") or config_model or DEFAULT_MODEL - if _parse_value_option(args, "--model", "-m") is None and not config_model: - args.extend(["--model", model]) - - configured_base_url = (config.inference_url or "").strip().rstrip("/") - config_client = config_data.get("client") if isinstance(config_data, dict) else None - config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None - cli_base_url = _parse_value_option(args, "--client.base-url", None) - base_url = cli_base_url or config_base_url or configured_base_url - if not base_url: - console.print( - "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." - ) - raise typer.Exit(1) - if cli_base_url is None and not config_base_url: - args.extend(["--client.base-url", base_url]) - # mirror v1 bool-flag semantics: a bare --dry-run (no value, or followed by - # another flag) means true; only an explicit false-y literal disables it - dry_run = config_data.get("dry_run") is True - for idx, arg in enumerate(args): - if arg == "--dry-run": - value = args[idx + 1].lower() if idx + 1 < len(args) else "" - dry_run = value not in ("false", "0") - elif arg.startswith("--dry-run="): - dry_run = arg.split("=", 1)[1].lower() not in ("false", "0") - if not dry_run: - _validate_model(model, base_url, configured_base_url) - _preflight_inference_billing(model, base_url, configured_base_url) - - env_dir_path = _env_dir_path_arg(args) - if _parse_value_option(args, "--env-dir-path", None) is not None: - env_dir_index = next( - idx - for idx, arg in enumerate(args) - if arg == "--env-dir-path" or arg.startswith("--env-dir-path=") - ) - if args[env_dir_index] == "--env-dir-path": - del args[env_dir_index : env_dir_index + 2] - else: - del args[env_dir_index] - upstream_slug: Optional[str] = None - env_name_for_upload: Optional[str] = None - resolved_env: Optional[ResolvedEnvironment] = None - config_envs: list[tuple[str, str]] = [] - - if is_config: - taskset = config_data.get("taskset") - env_ref = taskset.get("id") if isinstance(taskset, dict) else None - if not (isinstance(env_ref, str) and env_ref): - # v1's legacy field: a top-level `id` runs a v0 env through the bridge - env_ref = config_data.get("id") - if isinstance(env_ref, str) and env_ref: - config_envs = [(env_ref, env_dir_path)] - for config_env_ref, ref_env_dir in config_envs: - _prepare_v1_environment(plugin, config_env_ref, ref_env_dir) - # pydantic-config only reads a root config file as two tokens: `@ path` - run_args = ["@", target] - else: - resolved_env = _prepare_v1_environment(plugin, target, env_dir_path) - # hub refs (org/name[@version]) pass through verbatim; verifiers installs them - run_args = [resolved_env.install_slug or resolved_env.env_name] - upstream_slug = resolved_env.upstream_slug - env_name_for_upload = resolved_env.env_name - - job_target = env_name_for_upload - if job_target is None and config_envs: - job_target = _env_name_from_reference(config_envs[0][0]) - if job_target is None: - job_target = Path(target).stem - job_id = _build_job_id(job_target, model) - output_dir_arg = _parse_value_option(args, "--output-dir", "-o") - config_output_dir = config_data.get("output_dir") if isinstance(config_data, dict) else None - configured_output_dir = output_dir_arg or config_output_dir - output_dir = ( - Path(configured_output_dir) - if configured_output_dir - else Path("outputs", "evals", f"{job_target}--{model.replace('/', '--')}", job_id) + try: + v1_config, warnings = build_v1_eval_config(fields, tui_disabled=tui_disabled) + except ValueError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + for warning in warnings: + console.print(f"[yellow]Warning:[/yellow] {warning}") + + if resolved.env_display_id: + headers = v1_config.setdefault("client", {}).setdefault("headers", {}) + headers.setdefault(INTERNAL_ENV_DISPLAY_HEADER, resolved.env_display_id) + config_path = write_converted_eval_config( + v1_config, header_comment="converted from the v0 eval surface by prime" + ) + console.print(f"[dim]Converted v0 eval invocation to {config_path}[/dim]") + return config_path, resolved + + +def _run_converted_v0_eval( + environment: str, + passthrough_args: list[str], + config: Config, + *, + tui_disabled: bool, +) -> V1EvalRun: + """Run a frozen v0 invocation (hosted argv and/or a transitional TOML) on the v1 CLI. + + Classic env ids route through verifiers' legacy bridge automatically, so the + converted config never has to tag the environment generation.""" + from .utils.verifiers_v0_cli import v0_argv_to_fields + + try: + argv_fields = v0_argv_to_fields(environment, passthrough_args) + except SystemExit as exc: + raise typer.Exit(exc.code if isinstance(exc.code, int) else 2) from exc + target = str(argv_fields.pop("env_target")) + + fields: dict = {} + is_config = _is_config_target(target) + if is_config: + fields = _load_transitional_fields(Path(target)) + else: + # bare env id: verifiers auto-detects v0 envs given as the taskset id + fields["taskset"] = {"id": target} + fields.update(argv_fields) + + config_path, resolved = _write_converted_v1_config(fields, tui_disabled=tui_disabled) + run = _run_v1_eval(str(config_path), [], config) + if not is_config: + # keep bare-env upload attribution: this run is config-driven only as plumbing + run = replace( + run, is_config=False, resolved_env=resolved, upstream_slug=resolved.upstream_slug ) - if configured_output_dir is None: - args.extend(["--output-dir", str(output_dir)]) + return run + - headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} - if not isinstance(headers, dict): - console.print("[red]Error:[/red] client.headers must be a table") +def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config) -> V1EvalRun: + """Re-run `--resume ` and recover the upload identity from the run's config.toml.""" + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + plugin = load_verifiers_prime_plugin() + _run_command(plugin.build_module_command(plugin.eval_module, passthrough_args), env=env) + + output_dir = Path(resume_dir) + saved_config = toml.load(output_dir / "config.toml") + model = saved_config["model"] + env_name = _env_name_from_reference(saved_config["taskset"]["id"]) + saved_headers = saved_config.get("client", {}).get("headers", {}) + display_id = saved_headers.get(INTERNAL_ENV_DISPLAY_HEADER) + # display values like "name (local - ahead of org/name)" carry a "/" but are not slugs + is_slug = isinstance(display_id, str) and "/" in display_id and " " not in display_id + return V1EvalRun( + output_dir=output_dir, + job_id=saved_headers.get("X-PI-Job-Id") or _build_job_id(env_name, model), + env_name=env_name, + upstream_slug=display_id if is_slug else None, + ) + + +def _run_v1_eval( + environment: str, + passthrough_args: list[str], + config: Config, + *, + tui_disabled: bool = False, +) -> V1EvalRun: + """Prepare and run a fresh v1 eval: fill in prime's model/base-url/output-dir defaults, + make the environment importable, and tag the run with a job id header.""" + target = environment.removeprefix("@") + is_config = _is_config_target(target) + args = list(passthrough_args) + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + + config_data: dict = toml.load(target) if is_config else {} + if "env_id" in config_data or "eval" in config_data: + # a transitional/hosted v0 config (`env_id` / `[[eval]]`): convert it in place + fields = _load_transitional_fields(Path(target)) + target = str(_write_converted_v1_config(fields, tui_disabled=tui_disabled)[0]) + tui_disabled = False # the converted config already sets rich = false + config_data = toml.load(target) + if tui_disabled: + args.extend(["--rich", "false"]) + config_model = config_data.get("model") + cli_model = _parse_value_option(args, "--model", "-m") + model = cli_model or config_model or DEFAULT_MODEL + if cli_model is None and not config_model: + args.extend(["--model", model]) + + configured_base_url = (config.inference_url or "").strip().rstrip("/") + config_client = config_data.get("client") + config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None + cli_base_url = _parse_value_option(args, "--client.base-url", None) + base_url = cli_base_url or config_base_url or configured_base_url + if not base_url: + console.print( + "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." + ) + raise typer.Exit(1) + if cli_base_url is None and not config_base_url: + args.extend(["--client.base-url", base_url]) + + # mirror v1 bool-flag semantics: a bare --dry-run (no value, or followed by + # another flag) means true; only an explicit false-y literal disables it + dry_run = config_data.get("dry_run") is True + for idx, arg in enumerate(args): + if arg == "--dry-run": + value = args[idx + 1].lower() if idx + 1 < len(args) else "" + dry_run = value not in ("false", "0") + elif arg.startswith("--dry-run="): + dry_run = arg.split("=", 1)[1].lower() not in ("false", "0") + if not dry_run: + _validate_model(model, base_url, configured_base_url) + _preflight_inference_billing(model, base_url, configured_base_url) + + # prime-only option: verifiers must not see it + env_dir_path = _pop_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH + resolved_env: Optional[ResolvedEnvironment] = None + upstream_slug: Optional[str] = None + + if is_config: + taskset = config_data.get("taskset") + env_ref = taskset.get("id") if isinstance(taskset, dict) else None + if not (isinstance(env_ref, str) and env_ref): + # v1's legacy field: a top-level `id` runs a v0 env through the bridge + env_ref = config_data.get("id") + if isinstance(env_ref, str) and env_ref: + _prepare_v1_environment(env_ref, env_dir_path) + job_target = _env_name_from_reference(env_ref) + else: + job_target = Path(target).stem + # pydantic-config only reads a root config file as two tokens: `@ path` + run_args = ["@", target] + else: + resolved_env = _prepare_v1_environment(target, env_dir_path) + # the v1 CLI accepts only locally importable ids; hub refs were installed above + run_args = [resolved_env.env_name] + upstream_slug = resolved_env.upstream_slug + job_target = resolved_env.env_name + + job_id = _build_job_id(job_target, model) + output_dir_arg = _parse_value_option(args, "--output-dir", "-o") + configured_output_dir = output_dir_arg or config_data.get("output_dir") + output_dir = ( + Path(configured_output_dir) + if configured_output_dir + else Path("outputs", "evals", f"{job_target}--{model.replace('/', '--')}", job_id) + ) + if configured_output_dir is None: + args.extend(["--output-dir", str(output_dir)]) + + headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} + if not isinstance(headers, dict): + console.print("[red]Error:[/red] client.headers must be a table") + raise typer.Exit(2) + cli_headers = _pop_value_option(args, "--client.headers") + if cli_headers: + try: + parsed_headers = json.loads(cli_headers) + except json.JSONDecodeError as exc: + console.print("[red]Error:[/red] --client.headers must be valid JSON") + raise typer.Exit(2) from exc + if not isinstance(parsed_headers, dict): + console.print("[red]Error:[/red] --client.headers must be a JSON object") raise typer.Exit(2) - cli_headers = _parse_value_option(args, "--client.headers", None) - if cli_headers: - try: - parsed_headers = json.loads(cli_headers) - except json.JSONDecodeError as exc: - console.print("[red]Error:[/red] --client.headers must be valid JSON") - raise typer.Exit(2) from exc - if not isinstance(parsed_headers, dict): - console.print("[red]Error:[/red] --client.headers must be a JSON object") - raise typer.Exit(2) - headers = {**headers, **parsed_headers} - header_index = next( - idx - for idx, arg in enumerate(args) - if arg == "--client.headers" or arg.startswith("--client.headers=") - ) - if args[header_index] == "--client.headers": - del args[header_index : header_index + 2] - else: - del args[header_index] - headers["X-PI-Job-Id"] = job_id - if resolved_env is not None and resolved_env.env_display_id: - headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id - args.extend(["--client.headers", json.dumps(headers)]) - - console.print(f"[dim]Eval job_id: {job_id}[/dim]") - command = plugin.build_module_command(plugin.eval_module, [*run_args, *args]) - _run_command(command, env=env) - - results_path = output_dir / "results.jsonl" - if not results_path.exists(): + headers = {**headers, **parsed_headers} + headers["X-PI-Job-Id"] = job_id + if resolved_env is not None and resolved_env.env_display_id: + headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id + args.extend(["--client.headers", json.dumps(headers)]) + + console.print(f"[dim]Eval job_id: {job_id}[/dim]") + plugin = load_verifiers_prime_plugin() + _run_command(plugin.build_module_command(plugin.eval_module, [*run_args, *args]), env=env) + return V1EvalRun( + output_dir=output_dir, + job_id=job_id, + env_name=job_target, + upstream_slug=upstream_slug, + resolved_env=resolved_env, + is_config=is_config, + ) + + +def _upload_v1_results(run: V1EvalRun, *, skip_upload: bool, env_path: Optional[str]) -> None: + """Read the run's artifacts once (via verifiers), keep the lab view indexed, and upload.""" + if not (run.output_dir / "results.jsonl").exists(): console.print("[dim]No rollout results produced.[/dim]") return - results = convert_eval_results(load_results_jsonl(results_path)) + + from verifiers.v1.cli.output import read_upload_data + + upload = read_upload_data(run.output_dir) + + # `prime eval view` only lists runs that have a metadata.json; keep writing one. rollout_counts: dict[object, int] = {} - for row in results: + for row in upload.results: if "example_id" in row: - example_id = row["example_id"] - rollout_counts[example_id] = rollout_counts.get(example_id, 0) + 1 - rewards = [row["reward"] for row in results if isinstance(row.get("reward"), (int, float))] + rollout_counts[row["example_id"]] = rollout_counts.get(row["example_id"], 0) + 1 metadata = { - "env": job_target, - "model": model, + "env": run.env_name, + "model": upload.model_name, "num_examples": len(rollout_counts), - "avg_reward": sum(rewards) / len(rewards) if rewards else 0.0, + "avg_reward": upload.metrics.get("reward", 0.0), } rollout_totals = set(rollout_counts.values()) if len(rollout_totals) == 1: metadata["rollouts_per_example"] = rollout_totals.pop() - (output_dir / "metadata.json").write_text( + (run.output_dir / "metadata.json").write_text( json.dumps(metadata, indent=2) + "\n", encoding="utf-8" ) if skip_upload: - _print_environment_source_footer(resolved_env) + _print_environment_source_footer(run.resolved_env) console.print("[dim]Skipped uploading evaluation results[/dim]") return - if is_config: + if run.is_config: console.print( "[yellow]Evaluation completed. Automatic upload is skipped for " "config-driven runs.[/yellow]" ) return - if resolved_env is not None and resolved_env.recommend_push: - _print_environment_source_footer(resolved_env) + if run.resolved_env is not None and run.resolved_env.recommend_push: + _print_environment_source_footer(run.resolved_env) console.print( "[yellow]Evaluation completed. Automatic upload is skipped until the local " "environment is published.[/yellow]" ) return - upload_env_name = env_name_for_upload or environment - if upstream_slug is None: - check_path = Path(env_path) if env_path else Path.cwd() - metadata = find_environment_metadata( - env_name=upload_env_name, - env_path=check_path, - module_name=upload_env_name.replace("-", "_"), - ) - if metadata and metadata.get("owner") and metadata.get("name"): - upstream_slug = f"{metadata.get('owner')}/{metadata.get('name')}" - console.print(f"[dim]Using upstream environment {upstream_slug}[/dim]") - - if upstream_slug is None: - _print_environment_source_footer(resolved_env) - console.print( - "[dim]No upstream environment found. " - "Skipped uploading evaluation results to platform.\n" - "Use `prime env push` to set an upstream, or use `--env-path` to specify the " - "correct environment path.[/dim]" - ) - return - - if resolved_env is not None and resolved_env.platform_url: - console.print(f"[dim]Environment URL: {resolved_env.platform_url}[/dim]") + if run.resolved_env is not None and run.resolved_env.platform_url: + console.print(f"[dim]Environment URL: {run.resolved_env.platform_url}[/dim]") try: push_eval_results_to_hub( - env_name=upload_env_name, - model=model, - job_id=job_id, + env_name=run.env_name, + job_id=run.job_id, + upload=upload, env_path=Path(env_path) if env_path else None, - upstream_slug=upstream_slug, - output_dir=output_dir, + upstream_slug=run.upstream_slug, ) except Exception as exc: console.print(f"[red]Failed to push results to hub:[/red] {exc}") @@ -1249,7 +1311,7 @@ def run_eval_passthrough( def run_gepa_passthrough(environment_or_config: str, passthrough_args: list[str]) -> None: - plugin = load_verifiers_prime_plugin(console=console) + plugin = load_verifiers_prime_plugin() config = Config() if not config.api_key: @@ -1266,9 +1328,9 @@ def run_gepa_passthrough(environment_or_config: str, passthrough_args: list[str] if _is_config_target(environment_or_config): config_env = _collect_gepa_config_env(Path(environment_or_config), env_dir_path) if config_env is not None: - _prepare_single_environment(plugin, config_env[0], config_env[1]) + _prepare_single_environment(config_env[0], config_env[1]) else: - resolved = _prepare_single_environment(plugin, environment_or_config, env_dir_path) + resolved = _prepare_single_environment(environment_or_config, env_dir_path) run_target = resolved.env_name command = plugin.build_module_command(plugin.gepa_module, [run_target, *args]) diff --git a/packages/prime/src/prime_cli/verifiers_plugin.py b/packages/prime/src/prime_cli/verifiers_plugin.py index 705bdf277..b8dc17f78 100644 --- a/packages/prime/src/prime_cli/verifiers_plugin.py +++ b/packages/prime/src/prime_cli/verifiers_plugin.py @@ -1,8 +1,7 @@ -"""Compatibility layer for verifiers prime plugin loading.""" +"""Locate a verifiers-capable Python and build verifiers CLI commands.""" from __future__ import annotations -import importlib import os import subprocess import sys @@ -11,16 +10,17 @@ from pathlib import Path from typing import Sequence -from rich.console import Console - -from .utils.plain import get_console - -EXPECTED_PLUGIN_API_VERSION = 1 V1_EVAL_MODULE = "verifiers.v1.cli.eval.main" V1_INIT_MODULE = "verifiers.v1.cli.init" +V1_VALIDATE_MODULE = "verifiers.v1.cli.validate" +# `python -m` needs a `__main__` guard the v1 modules only gained recently; these -c +# shims call `main()` directly so they work across verifiers versions. V1_ENTRYPOINTS = { V1_EVAL_MODULE: f"import sys; sys.argv[0] = 'eval'; from {V1_EVAL_MODULE} import main; main()", V1_INIT_MODULE: f"import sys; sys.argv[0] = 'init'; from {V1_INIT_MODULE} import main; main()", + V1_VALIDATE_MODULE: ( + f"import sys; sys.argv[0] = 'validate'; from {V1_VALIDATE_MODULE} import main; main()" + ), } @@ -83,16 +83,14 @@ def _usable(candidate: Path) -> bool: @dataclass(frozen=True) class PrimeVerifiersPlugin: - """Local fallback contract used when verifiers plugin loading fails.""" + """The verifiers CLI modules prime shells out to.""" - api_version: int = EXPECTED_PLUGIN_API_VERSION eval_module: str = V1_EVAL_MODULE + init_module: str = V1_INIT_MODULE + validate_module: str = V1_VALIDATE_MODULE gepa_module: str = "verifiers.cli.commands.gepa" install_module: str = "verifiers.cli.commands.install" - init_module: str = V1_INIT_MODULE - setup_module: str = "verifiers.cli.commands.setup" build_module: str = "verifiers.cli.commands.build" - tui_module: str = "verifiers.cli.tui" def build_module_command( self, module_name: str, args: Sequence[str] | None = None @@ -105,50 +103,7 @@ def build_module_command( return command -def load_verifiers_prime_plugin(console: Console | None = None) -> PrimeVerifiersPlugin: - """Load plugin exported by verifiers with fallback behavior.""" - sink = console or get_console(stderr=True) - try: - module = importlib.import_module("verifiers.cli.plugins.prime") - except Exception as exc: - sink.print( - "[yellow]Warning:[/yellow] Could not import verifiers prime plugin " - f"({exc}). Falling back to built-in command mapping." - ) - return PrimeVerifiersPlugin() - - get_plugin = getattr(module, "get_plugin", None) - if not callable(get_plugin): - sink.print( - "[yellow]Warning:[/yellow] verifiers prime plugin module does not expose " - "a callable get_plugin(). Falling back to built-in command mapping." - ) - return PrimeVerifiersPlugin() - - try: - plugin = get_plugin() - except Exception as exc: - sink.print( - "[yellow]Warning:[/yellow] Failed to load verifiers plugin " - f"({exc}). Falling back to built-in command mapping." - ) - return PrimeVerifiersPlugin() - - api_version = getattr(plugin, "api_version", None) - if api_version != EXPECTED_PLUGIN_API_VERSION: - sink.print( - "[yellow]Warning:[/yellow] verifiers plugin API version mismatch " - f"(got {api_version}, expected {EXPECTED_PLUGIN_API_VERSION}). " - "Continuing with compatibility behavior." - ) - - return PrimeVerifiersPlugin( - api_version=int(api_version or EXPECTED_PLUGIN_API_VERSION), - eval_module=V1_EVAL_MODULE, - gepa_module=getattr(plugin, "gepa_module", "verifiers.cli.commands.gepa"), - install_module=getattr(plugin, "install_module", "verifiers.cli.commands.install"), - init_module=V1_INIT_MODULE, - setup_module=getattr(plugin, "setup_module", "verifiers.cli.commands.setup"), - build_module=getattr(plugin, "build_module", "verifiers.cli.commands.build"), - tui_module=getattr(plugin, "tui_module", "verifiers.cli.tui"), - ) +def load_verifiers_prime_plugin() -> PrimeVerifiersPlugin: + """The static verifiers command map. Verifiers no longer exports a plugin module; the + old import handshake always resolved to these values anyway.""" + return PrimeVerifiersPlugin() diff --git a/packages/prime/src/prime_lab_app/agent_widget_model.py b/packages/prime/src/prime_lab_app/agent_widget_model.py index c53020e89..3a13b4d28 100644 --- a/packages/prime/src/prime_lab_app/agent_widget_model.py +++ b/packages/prime/src/prime_lab_app/agent_widget_model.py @@ -1134,7 +1134,7 @@ def _widget_command_text(payload: dict[str, Any], workspace: Path) -> str: if config_kind == "rl": return f"prime train run {rel_path} --yes" if config_kind == "eval": - return f"prime eval run {rel_path} --hosted" + return f"prime eval {rel_path} --hosted" if config_kind == "gepa": return f"prime gepa run {rel_path}" return "" diff --git a/packages/prime/src/prime_lab_app/config_screen.py b/packages/prime/src/prime_lab_app/config_screen.py index d1b1a301f..822f0a8c4 100644 --- a/packages/prime/src/prime_lab_app/config_screen.py +++ b/packages/prime/src/prime_lab_app/config_screen.py @@ -1078,7 +1078,7 @@ def _launch_command(config_kind: str, rel_path: str) -> str: if config_kind == "rl": return f"prime train run {quoted_path} --yes" if config_kind == "eval": - return f"prime eval run {quoted_path} --hosted" + return f"prime eval {quoted_path} --hosted" return f"prime gepa run {quoted_path}" diff --git a/packages/prime/src/prime_lab_app/data.py b/packages/prime/src/prime_lab_app/data.py index 7c6254495..2155ea056 100644 --- a/packages/prime/src/prime_lab_app/data.py +++ b/packages/prime/src/prime_lab_app/data.py @@ -1718,7 +1718,7 @@ def _workspace_config_command(config_kind: str, rel_path: str) -> str: if config_kind == "rl": return f"prime train run {rel_path} --yes" if config_kind == "eval": - return f"prime eval run {rel_path} --hosted" + return f"prime eval {rel_path} --hosted" return f"prime gepa run {rel_path}" diff --git a/packages/prime/tests/test_env_push_path.py b/packages/prime/tests/test_env_push_path.py index f16823f74..3c40a93e1 100644 --- a/packages/prime/tests/test_env_push_path.py +++ b/packages/prime/tests/test_env_push_path.py @@ -130,7 +130,7 @@ def build_module_command(self, module, args): monkeypatch.setattr( "prime_cli.commands.env.load_verifiers_prime_plugin", - lambda console: DummyPlugin(), + lambda: DummyPlugin(), ) def fake_run(command, *args, **kwargs): diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index a0893af3f..a2b86b5f4 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -3,6 +3,7 @@ import httpx import pytest +import toml import typer from prime_cli.api.inference import ( InferenceAPIError, @@ -78,7 +79,7 @@ def get(self, url): ) def test_eval_run_blocks_when_inference_billing_is_missing(monkeypatch, error_message): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) @@ -107,7 +108,7 @@ def chat_completion(self, payload, stream=False): def test_eval_preflight_omits_max_tokens(monkeypatch): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) seen_payloads = [] @@ -152,7 +153,7 @@ def chat_completion(self, payload, stream=False): def test_eval_run_uses_v1_client_config(monkeypatch, tmp_path): monkeypatch.chdir(tmp_path) monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) @@ -164,7 +165,7 @@ def __init__(self, timeout=None): monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda _plugin, env_name, env_dir: ( + lambda env_name, env_dir: ( captured.update(prepared=(env_name, env_dir)) or ResolvedEnvironment( original=env_name, @@ -212,9 +213,9 @@ def __init__(self, timeout=None): @pytest.mark.parametrize("save_flag", ["--save-results", "-s"]) -def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch, save_flag): +def test_eval_run_legacy_save_results_converts_to_v1(monkeypatch, save_flag): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) @@ -222,7 +223,7 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch, save_flag) "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None ) monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_single_environment", + "prime_cli.verifiers_bridge._prepare_v1_environment", lambda *_args: ResolvedEnvironment( original="legacy-env", env_name="legacy-env", install_mode="local" ), @@ -237,8 +238,6 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch, save_flag) environment="legacy-env", passthrough_args=[ save_flag, - "--resume", - "/tmp/legacy-results.jsonl", "--debug", "--num-examples", "1", @@ -249,16 +248,43 @@ def test_eval_run_legacy_save_results_uses_v0_entrypoint(monkeypatch, save_flag) env_path=None, ) - assert captured["command"][0] == "verifiers.cli.commands.eval" - assert save_flag in captured["command"] - assert "--resume" in captured["command"] - assert "--debug" in captured["command"] - assert "--client.headers" not in captured["command"] + # the frozen v0 surface now runs converted on the v1 entrypoint + assert captured["command"][0] == "verifiers.v1.cli.eval.main" + assert captured["command"][1] == "@" + converted = toml.load(captured["command"][2]) + assert converted["taskset"] == {"id": "legacy-env"} + assert converted["num_tasks"] == 1 + assert converted["num_rollouts"] == 2 + assert converted["rich"] is False # --debug means "no live display" + assert "--client.headers" in captured["command"] + + +def test_eval_run_v0_resume_is_rejected_with_guidance(monkeypatch): + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda *_args: ResolvedEnvironment( + original="legacy-env", env_name="legacy-env", install_mode="local" + ), + ) + + with pytest.raises(typer.Exit) as exc_info: + run_eval_passthrough( + environment="legacy-env", + passthrough_args=["-s", "--resume", "/tmp/legacy-results.jsonl"], + skip_upload=True, + env_path=None, + ) + + assert cast(typer.Exit, exc_info.value).exit_code == 2 def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr( @@ -310,14 +336,15 @@ def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): str(output_dir), ] assert captured["env"]["PRIME_API_KEY"] == "test-api-key" - assert captured["upload"] == { - "env_name": "wiki-search", - "model": "openai/gpt-4.1-mini", - "job_id": "existing-job-id", - "env_path": None, - "upstream_slug": "primeintellect/wiki-search", - "output_dir": output_dir, - } + upload_kwargs = captured["upload"] + assert upload_kwargs["env_name"] == "wiki-search" + assert upload_kwargs["job_id"] == "existing-job-id" + assert upload_kwargs["env_path"] is None + assert upload_kwargs["upstream_slug"] == "primeintellect/wiki-search" + upload = upload_kwargs["upload"] + assert upload.model_name == "openai/gpt-4.1-mini" + assert upload.env == "wiki-search" + assert upload.results == [{"id": 0, "reward": 1.0, "example_id": 0}] metadata = json.loads((output_dir / "metadata.json").read_text()) assert metadata["num_examples"] == 1 assert metadata["rollouts_per_example"] == 1 @@ -329,7 +356,7 @@ def test_eval_run_missing_endpoint_registry_falls_back_to_configured_inference( ): monkeypatch.chdir(tmp_path) monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) @@ -376,13 +403,13 @@ def chat_completion(self, payload, stream=False): def test_gepa_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) captured = {} monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_single_environment", - lambda _plugin, environment, env_dir_path: ( + lambda environment, env_dir_path: ( captured.update({"environment": environment, "env_dir_path": env_dir_path}) or ResolvedEnvironment( original=environment, @@ -406,7 +433,7 @@ def test_gepa_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch def test_eval_run_continues_when_model_validation_times_out(monkeypatch): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) @@ -443,7 +470,7 @@ def chat_completion(self, payload, stream=False): def test_eval_run_continues_when_billing_preflight_times_out(monkeypatch): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) @@ -481,7 +508,7 @@ def chat_completion(self, payload, stream=False): @pytest.mark.parametrize("prefix", ["", "@"]) def test_eval_config_uses_v1_taskset(monkeypatch, tmp_path, prefix): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) @@ -504,7 +531,7 @@ def test_eval_config_uses_v1_taskset(monkeypatch, tmp_path, prefix): prepared = [] commands = [] - def fake_prepare(_plugin, env_reference, env_dir_path): + def fake_prepare(env_reference, env_dir_path): prepared.append((env_reference, env_dir_path)) def fake_run_command(command, env=None): @@ -533,7 +560,7 @@ def fake_run_command(command, env=None): def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_config): monkeypatch.chdir(tmp_path) monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr( @@ -546,7 +573,7 @@ def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_conf ) monkeypatch.setattr( "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda _plugin, environment, _env_dir: ResolvedEnvironment( + lambda environment, _env_dir: ResolvedEnvironment( original=environment, env_name=environment, install_mode="local", @@ -579,7 +606,7 @@ def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_conf def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) @@ -599,6 +626,10 @@ def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): def fake_run(command, env=None): captured["command"] = command output_dir.mkdir() + # a real run writes its resolved config.toml alongside the results + (output_dir / "config.toml").write_text( + 'model = "openai/gpt-4.1-mini"\n\n[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8" + ) (output_dir / "results.jsonl").write_text( json.dumps( {"task": {"idx": 0, "prompt": None}, "nodes": [], "rewards": {"correct": 1.0}} @@ -630,7 +661,7 @@ def fake_run(command, env=None): def test_eval_writes_v1_metadata(monkeypatch, tmp_path, task_ids, expected_rollouts): monkeypatch.chdir(tmp_path) monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda console: DummyPlugin() + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() ) monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) @@ -652,6 +683,10 @@ def fake_run(command, env=None): captured["command"] = command output_dir = Path(command[command.index("--output-dir") + 1]) output_dir.mkdir(parents=True) + # a real run writes its resolved config.toml alongside the results + (output_dir / "config.toml").write_text( + 'model = "openai/gpt-4.1-mini"\n\n[taskset]\nid = "wiki-search"\n', encoding="utf-8" + ) rewards = [1.0, 0.5, 0.75] rows = [ { diff --git a/packages/prime/tests/test_eval_help.py b/packages/prime/tests/test_eval_help.py index 1b1004718..3ccf8d377 100644 --- a/packages/prime/tests/test_eval_help.py +++ b/packages/prime/tests/test_eval_help.py @@ -11,8 +11,9 @@ def fake_help() -> None: print("BACKEND_HELP") monkeypatch.setattr("prime_cli.commands.evals.print_eval_run_help", fake_help) - for flag in ("-h", "--help"): - result = runner.invoke(app, ["eval", "run", flag], env={"PRIME_DISABLE_VERSION_CHECK": "1"}) + # `prime eval` is the command; `run` stays as the hidden hosted-sandbox alias + for invocation in (["eval", "-h"], ["eval", "--help"], ["eval"], ["eval", "run", "--help"]): + result = runner.invoke(app, invocation, env={"PRIME_DISABLE_VERSION_CHECK": "1"}) assert result.exit_code == 0, result.output assert "BACKEND_HELP" in result.output @@ -35,9 +36,9 @@ def test_sanitize_help_removes_vf_eval_aliases(): "usage: python -m verifiers.cli.commands.eval [-h] env_id_or_config\n" "Run vf-eval with verifiers.cli.commands.eval\n" ) - help_text = _sanitize_help_text(raw, "verifiers.cli.commands.eval", "prime eval run") + help_text = _sanitize_help_text(raw, "verifiers.cli.commands.eval", "prime eval") - assert "Usage: prime eval run [-h] environment" in help_text + assert "Usage: prime eval [-h] environment" in help_text assert "verifiers.cli.commands.eval" not in help_text assert "vf-eval" not in help_text assert "env_id_or_config" not in help_text @@ -46,9 +47,9 @@ def test_sanitize_help_removes_vf_eval_aliases(): def test_sanitize_help_rewrites_v1_console_script(): raw = "usage: uv run eval []\nusage: main.py [-h] [@ FILE] [OPTIONS]\n" - help_text = _sanitize_help_text(raw, "verifiers.v1.cli.eval.main", "prime eval run") + help_text = _sanitize_help_text(raw, "verifiers.v1.cli.eval.main", "prime eval") - assert help_text.count("Usage: prime eval run") == 2 + assert help_text.count("Usage: prime eval") == 2 assert "uv run eval" not in help_text @@ -64,7 +65,7 @@ def test_v1_module_command_calls_console_entrypoint(monkeypatch): def test_append_eval_options_mentions_tunnel_access(): - help_text = _append_eval_options("Usage: prime eval run [-h] environment\n") + help_text = _append_eval_options("Usage: prime eval [-h] environment\n") assert "--allow-tunnel-access" in help_text diff --git a/packages/prime/tests/test_eval_push.py b/packages/prime/tests/test_eval_push.py index 18212f802..4a0a18628 100644 --- a/packages/prime/tests/test_eval_push.py +++ b/packages/prime/tests/test_eval_push.py @@ -3,189 +3,16 @@ import pytest import typer from prime_cli.commands.evals import ( - _has_eval_files, - _load_eval_directory, _push_samples_with_progress, _push_single_eval, - _validate_eval_path, ) from prime_cli.main import app -from prime_cli.utils.eval_push import convert_eval_results from typer.testing import CliRunner from typing_extensions import cast runner = CliRunner() -def test_convert_eval_results_supports_v1_and_legacy_samples(): - samples = [ - {"id": 3, "reward": 0.5, "completion": "legacy"}, - { - "id": "trace-1", - "task": {"idx": 7, "prompt": "What is 2 + 2?", "answer": "4"}, - "nodes": [ - { - "message": {"role": "user", "content": "What is 2 + 2?"}, - "token_ids": [1, 2], - "mask": [False, False], - }, - { - "parent": 0, - "message": {"role": "assistant", "content": "4"}, - "sampled": True, - "token_ids": [3, 4], - "mask": [False, True], - "logprobs": [-0.1], - }, - ], - "rewards": {"correct": 1.0}, - "metrics": {"exact_match": 1.0}, - "info": {"source": "test"}, - "is_completed": True, - "grader_note": "kept as metadata", - }, - ] - - legacy, v1 = convert_eval_results(samples) - - assert legacy == { - "id": 3, - "example_id": 3, - "reward": 0.5, - "completion": "legacy", - } - assert v1["sample_id"] == "trace-1" - assert v1["example_id"] == 7 - assert v1["rollout_number"] == 1 - assert v1["answer"] == "4" - assert v1["reward"] == 1.0 - assert v1["completion"][-1] == {"role": "assistant", "content": "4"} - assert v1["trajectory"] == [ - { - "messages": [ - {"role": "user", "content": "What is 2 + 2?"}, - {"role": "assistant", "content": "4"}, - ], - "reward": 1.0, - "num_input_tokens": 3, - "num_output_tokens": 1, - } - ] - assert v1["info"] == {"source": "test", "grader_note": "kept as metadata"} - - -class TestHasEvalFiles: - """Tests for _has_eval_files function""" - - def test_has_both_files(self, tmp_path): - """Directory with both files returns True""" - (tmp_path / "metadata.json").write_text("{}") - (tmp_path / "results.jsonl").write_text("") - assert _has_eval_files(tmp_path) is True - - def test_missing_metadata(self, tmp_path): - """Directory missing metadata.json returns False""" - (tmp_path / "results.jsonl").write_text("") - assert _has_eval_files(tmp_path) is False - - def test_missing_results(self, tmp_path): - """Directory missing results.jsonl returns False""" - (tmp_path / "metadata.json").write_text("{}") - assert _has_eval_files(tmp_path) is False - - def test_empty_directory(self, tmp_path): - """Empty directory returns False""" - assert _has_eval_files(tmp_path) is False - - -class TestValidateEvalPath: - """Tests for _validate_eval_path function""" - - def test_valid_directory(self, tmp_path): - """Valid directory with both files returns the path""" - (tmp_path / "metadata.json").write_text("{}") - (tmp_path / "results.jsonl").write_text("") - result = _validate_eval_path(str(tmp_path)) - assert result == tmp_path - - def test_metadata_file_autocorrects_to_parent(self, tmp_path): - """Passing metadata.json auto-corrects to parent directory""" - (tmp_path / "metadata.json").write_text("{}") - (tmp_path / "results.jsonl").write_text("") - - result = _validate_eval_path(str(tmp_path / "metadata.json")) - assert result == tmp_path - - def test_results_file_autocorrects_to_parent(self, tmp_path): - """Passing results.jsonl auto-corrects to parent directory""" - (tmp_path / "metadata.json").write_text("{}") - (tmp_path / "results.jsonl").write_text("") - - result = _validate_eval_path(str(tmp_path / "results.jsonl")) - assert result == tmp_path - - def test_metadata_file_without_results_errors(self, tmp_path): - """Passing metadata.json when results.jsonl missing raises error""" - (tmp_path / "metadata.json").write_text("{}") - - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(tmp_path / "metadata.json")) - - assert "must contain both metadata.json and results.jsonl" in str(exc_info.value) - - def test_results_file_without_metadata_errors(self, tmp_path): - """Passing results.jsonl when metadata.json missing raises error""" - (tmp_path / "results.jsonl").write_text("") - - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(tmp_path / "results.jsonl")) - - assert "must contain both metadata.json and results.jsonl" in str(exc_info.value) - - def test_random_file_errors(self, tmp_path): - """Passing a random file raises descriptive error""" - random_file = tmp_path / "random.txt" - random_file.write_text("hello") - - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(random_file)) - - assert "Expected a directory path" in str(exc_info.value) - assert "random.txt" in str(exc_info.value) - - def test_directory_missing_results(self, tmp_path): - """Directory with only metadata.json raises specific error""" - (tmp_path / "metadata.json").write_text("{}") - - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(tmp_path)) - - assert "missing results.jsonl" in str(exc_info.value) - - def test_directory_missing_metadata(self, tmp_path): - """Directory with only results.jsonl raises specific error""" - (tmp_path / "results.jsonl").write_text("") - - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(tmp_path)) - - assert "missing metadata.json" in str(exc_info.value) - - def test_directory_missing_both(self, tmp_path): - """Empty directory raises error mentioning both files""" - with pytest.raises(ValueError) as exc_info: - _validate_eval_path(str(tmp_path)) - - assert "missing both metadata.json and results.jsonl" in str(exc_info.value) - - def test_nonexistent_path(self): - """Nonexistent path raises FileNotFoundError""" - with pytest.raises(FileNotFoundError) as exc_info: - _validate_eval_path("/nonexistent/path/xyz123") - - assert "Path not found" in str(exc_info.value) - - def test_push_eval_rejects_public_with_eval_id(monkeypatch, tmp_path): monkeypatch.chdir(tmp_path) monkeypatch.setattr("prime_cli.main.check_for_update", lambda: (False, None)) @@ -370,6 +197,40 @@ def finalize_evaluation(self, evaluation_id, metrics=None): assert captured["is_public"] is False assert captured["environments"] == [{"slug": "owner/gsm8k"}] + def test_push_supports_native_v1_run(self, tmp_path, monkeypatch): + """A native verifiers run (config.toml, no metadata.json) is pushable directly.""" + (tmp_path / "config.toml").write_text( + 'model = "gpt-4"\nnum_tasks = 1\nnum_rollouts = 1\n\n[taskset]\nid = "gsm8k-v1"\n' + ) + (tmp_path / "results.jsonl").write_text(json.dumps({"id": 1, "reward": 1.0}) + "\n") + + captured = {} + + class DummyEvalsClient: + def __init__(self, _api_client): + pass + + def create_evaluation(self, **kwargs): + captured.update(kwargs) + return {"evaluation_id": "eval-123"} + + def push_samples(self, evaluation_id, samples): + captured["samples"] = samples + + def finalize_evaluation(self, evaluation_id, metrics=None): + captured["finalized_metrics"] = metrics + + monkeypatch.setattr("prime_cli.commands.evals.APIClient", lambda: object()) + monkeypatch.setattr("prime_cli.commands.evals.EvalsClient", DummyEvalsClient) + + eval_id = _push_single_eval(str(tmp_path), "owner/gsm8k", None, None) + + assert eval_id == "eval-123" + assert captured["name"] == "gsm8k-v1-gpt-4" + assert captured["model_name"] == "gpt-4" + assert captured["metrics"] == {"reward": 1.0} + assert captured["samples"] == [{"id": 1, "reward": 1.0, "example_id": 1}] + def test_create_evaluation_requires_pushed_environment(self, tmp_path, capsys): metadata = {"env": "gsm8k", "model": "gpt-4"} (tmp_path / "metadata.json").write_text(json.dumps(metadata)) @@ -533,156 +394,5 @@ def finalize_evaluation(self, evaluation_id, metrics=None): assert "https://fallback.example/eval-123" in output -class TestLoadEvalDirectory: - """Tests for _load_eval_directory function""" - - def test_loads_valid_eval_data(self, tmp_path): - """Loads and parses valid eval directory""" - metadata = { - "env": "gsm8k", - "model": "gpt-4", - "avg_reward": 0.85, - "avg_accuracy": 0.9, - "num_examples": 100, - } - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - - results = [ - {"id": 0, "reward": 1.0, "answer": "42"}, - {"id": 1, "reward": 0.5, "answer": "18"}, - ] - (tmp_path / "results.jsonl").write_text("\n".join(json.dumps(r) for r in results)) - - data = _load_eval_directory(tmp_path) - - assert data["eval_name"] == "gsm8k-gpt-4" - assert data["model_name"] == "gpt-4" - assert data["env"] == "gsm8k" - assert data["metrics"] == {"reward": 0.85, "accuracy": 0.9} - assert data["metadata"]["num_examples"] == 100 - assert len(data["results"]) == 2 - assert data["results"][0]["example_id"] == 0 - assert data["results"][1]["example_id"] == 1 - - def test_uses_env_id_field(self, tmp_path): - """Uses env_id field if env is not present""" - metadata = {"env_id": "math-problems", "model": "claude-3"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - (tmp_path / "results.jsonl").write_text("") - - data = _load_eval_directory(tmp_path) - - assert data["eval_name"] == "math-problems-claude-3" - assert data["env"] == "math-problems" - - def test_missing_env_field_raises(self, tmp_path): - """Raises error if both env and env_id are missing""" - metadata = {"model": "gpt-4"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - (tmp_path / "results.jsonl").write_text("") - - with pytest.raises(ValueError) as exc_info: - _load_eval_directory(tmp_path) - - assert "env_id" in str(exc_info.value) - - def test_missing_model_field_raises(self, tmp_path): - """Raises error if model field is missing""" - metadata = {"env": "gsm8k"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - (tmp_path / "results.jsonl").write_text("") - - with pytest.raises(ValueError) as exc_info: - _load_eval_directory(tmp_path) - - assert "model" in str(exc_info.value) - - def test_skips_invalid_jsonl_lines_with_warning(self, tmp_path, capsys): - """Skips invalid JSON lines in results.jsonl and warns""" - metadata = {"env": "test", "model": "test-model"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - - results_content = '{"id": 0, "reward": 1.0}\ninvalid json line\n{"id": 1, "reward": 0.5}' - (tmp_path / "results.jsonl").write_text(results_content) - - data = _load_eval_directory(tmp_path) - - # Should only have 2 valid results, skipping the invalid line - assert len(data["results"]) == 2 - - # Should print a warning - captured = capsys.readouterr() - assert "Warning" in captured.out - assert "Skipped" in captured.out - - def test_skips_non_dict_jsonl_lines_with_warning(self, tmp_path, capsys): - """Skips non-dict JSON values in results.jsonl and warns""" - metadata = {"env": "test", "model": "test-model"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - - # Valid JSON but non-dict values (int, null, bool, string) - results_content = ( - '{"id": 0, "reward": 1.0}\n123\nnull\ntrue\n"string"\n{"id": 1, "reward": 0.5}' - ) - (tmp_path / "results.jsonl").write_text(results_content) - - data = _load_eval_directory(tmp_path) - - # Should only have 2 valid dict results - assert len(data["results"]) == 2 - assert data["results"][0]["example_id"] == 0 - assert data["results"][1]["example_id"] == 1 - - # Should print a warning about non-dict values - captured = capsys.readouterr() - assert "Warning" in captured.out - assert "Skipped 4" in captured.out - assert "expected dict" in captured.out - - def test_converts_id_to_example_id(self, tmp_path): - """Converts 'id' field to 'example_id' in results""" - metadata = {"env": "test", "model": "test-model"} - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - - results = [{"id": 42, "reward": 1.0}] - (tmp_path / "results.jsonl").write_text(json.dumps(results[0])) - - data = _load_eval_directory(tmp_path) - - assert data["results"][0]["example_id"] == 42 - assert data["results"][0]["id"] == 42 # Original field preserved - - def test_extracts_avg_metrics(self, tmp_path): - """Extracts avg_* fields into metrics dict""" - metadata = { - "env": "test", - "model": "test-model", - "avg_reward": 0.75, - "avg_correctness": 0.8, - "avg_format_reward": 0.95, - "other_field": "value", - } - (tmp_path / "metadata.json").write_text(json.dumps(metadata)) - (tmp_path / "results.jsonl").write_text("") - - data = _load_eval_directory(tmp_path) - - assert data["metrics"] == { - "reward": 0.75, - "correctness": 0.8, - "format_reward": 0.95, - } - assert "avg_reward" not in data["metadata"] - assert data["metadata"]["other_field"] == "value" - - def test_invalid_metadata_json_raises(self, tmp_path): - """Raises JSONDecodeError if metadata.json is invalid""" - (tmp_path / "metadata.json").write_text("not valid json {") - (tmp_path / "results.jsonl").write_text("") - - with pytest.raises(json.JSONDecodeError): - _load_eval_directory(tmp_path) - - if __name__ == "__main__": pytest.main([__file__, "-v"]) diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index 6c7ac1b52..a2d7d8581 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -4,6 +4,7 @@ import typer from prime_cli.client import APIError from prime_cli.commands.evals import ( + _build_hosted_evaluation_payload, _create_hosted_evaluations, _load_hosted_eval_configs, _print_eval_status, @@ -1839,3 +1840,98 @@ def test_eval_logs_command_emits_waiting_status_when_logs_are_unchanged(monkeypa assert result.output.count("Line 1") == 1 assert "Evaluation status: RUNNING (waiting for logs...)" in result.output assert "Status: COMPLETED" in result.output + + +V1_HOSTED_TOML = """\ +model = "openai/gpt-4.1-mini" +num_tasks = 7 +num_rollouts = 2 +max_concurrent = 16 + +[taskset] +id = "gsm8k-v1" +difficulty = "easy" + +[harness] +id = "default" + +[sampling] +temperature = 0.3 + +[retries.rollout] +max_retries = 2 + +[client.headers] +X-Custom = "yes" +""" + + +def test_eval_run_hosted_v1_config_sends_environments(monkeypatch, tmp_path): + captured = {} + + def fail_resolve(*args, **kwargs): + raise AssertionError("raw v1 hosted evals must not resolve a published environment") + + monkeypatch.setattr("prime_cli.commands.evals._resolve_hosted_environment", fail_resolve) + + def fake_create(config, environment_ids=None): + captured["payload"] = _build_hosted_evaluation_payload(config) + captured["environment_ids"] = environment_ids + return {"evaluation_id": "eval-123"} + + monkeypatch.setattr("prime_cli.commands.evals._create_hosted_evaluations", fake_create) + + config_path = tmp_path / "eval.toml" + config_path.write_text(V1_HOSTED_TOML) + result = runner.invoke( + app, + ["eval", str(config_path), "--hosted", "-n", "9"], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + + assert result.exit_code == 0, result.output + payload = captured["payload"] + assert "environment_ids" not in payload + assert payload["environments"] == [ + { + "taskset": {"id": "gsm8k-v1", "difficulty": "easy"}, + "harness": {"id": "default"}, + "retries": {"rollout": {"max_retries": 2}}, + "sampling": {"temperature": 0.3}, + } + ] + assert payload["eval_config"]["num_examples"] == 9 # CLI override wins over num_tasks + assert payload["eval_config"]["rollouts_per_example"] == 2 + assert payload["eval_config"]["max_concurrent"] == 16 + assert payload["eval_config"]["headers"] == ["X-Custom: yes"] + assert captured["environment_ids"] is None + assert "Hosted evaluation started" in result.output + + +def test_eval_run_hosted_v1_config_rejects_local_only_fields(monkeypatch, tmp_path): + config_path = tmp_path / "eval.toml" + config_path.write_text('output_dir = "outputs"\n\n[taskset]\nid = "gsm8k-v1"\n') + + result = runner.invoke( + app, + ["eval", "run", str(config_path), "--hosted"], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + + assert result.exit_code == 1 + assert "does not support" in result.output + assert "output_dir" in result.output + + +def test_eval_run_hosted_legacy_id_config_needs_published_env(monkeypatch, tmp_path): + config_path = tmp_path / "eval.toml" + config_path.write_text('id = "reverse-text"\nmodel = "openai/gpt-4.1-mini"\n') + + result = runner.invoke( + app, + ["eval", "run", str(config_path), "--hosted"], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + + assert result.exit_code == 1 + assert "published environment" in result.output diff --git a/packages/prime/tests/test_lab_setup.py b/packages/prime/tests/test_lab_setup.py index d0e63efd7..a2480db7c 100644 --- a/packages/prime/tests/test_lab_setup.py +++ b/packages/prime/tests/test_lab_setup.py @@ -347,7 +347,7 @@ def test_lab_setup_service_emits_post_setup_call_to_action( assert "ask codex" in output assert "I want to train a model for " in output assert "prime env init my-env" in output - assert "prime eval run my-env -m openai/gpt-5.4-nano -n 5" in output + assert "prime eval my-env -m openai/gpt-5.4-nano -n 5" in output assert "prime rl run configs/rl/qwen-3-5.toml" in output assert "prime gepa run my-env -m openai/gpt-5.4-nano" in output diff --git a/packages/prime/tests/test_lab_view.py b/packages/prime/tests/test_lab_view.py index bd1b2f33b..6f000bc10 100644 --- a/packages/prime/tests/test_lab_view.py +++ b/packages/prime/tests/test_lab_view.py @@ -5771,9 +5771,7 @@ async def test_prime_lab_app_chat_widget_launches_from_inline_config( command = launch_plan.command generated = tmp_path / ".prime" / "lab" / "configs" / "eval" / "reverse-text.toml" parsed = toml.loads(generated.read_text(encoding="utf-8")) - assert command == ( - "prime eval run .prime/lab/configs/eval/reverse-text.toml --hosted --follow" - ) + assert command == ("prime eval .prime/lab/configs/eval/reverse-text.toml --hosted --follow") assert parsed["model"] == "openai/gpt-4.1-mini" assert parsed["num_examples"] == 7 assert parsed["rollouts_per_example"] == 4 @@ -6456,7 +6454,7 @@ def stop(self) -> None: card = app.screen.query_one(AgentWidgetCard) launch_plan = card.current_launch_plan() assert launch_plan.command == ( - "prime eval run .prime/lab/configs/eval/reverse-text.toml --hosted --follow" + "prime eval .prime/lab/configs/eval/reverse-text.toml --hosted --follow" ) assert card._launch_running is False card.query_one(".agent-widget-action-launch", Button).press() @@ -6465,9 +6463,7 @@ def stop(self) -> None: log_text = _render_renderable(card.query_one(".agent-widget-log", Static).content) status_text = _render_renderable(card.query_one(".agent-widget-status", Static).content) - assert calls == [ - "prime eval run .prime/lab/configs/eval/reverse-text.toml --hosted --follow" - ] + assert calls == ["prime eval .prime/lab/configs/eval/reverse-text.toml --hosted --follow"] assert "launching" in log_text assert "done" in log_text assert "Completed" in status_text @@ -7331,7 +7327,6 @@ def test_launch_command_quotes_config_paths_with_spaces() -> None: assert shlex.split(launch_command_for_config("eval", "configs/eval/my eval.toml")) == [ "prime", "eval", - "run", "configs/eval/my eval.toml", "--hosted", ] diff --git a/packages/prime/tests/test_v0_compat.py b/packages/prime/tests/test_v0_compat.py new file mode 100644 index 000000000..765eeac18 --- /dev/null +++ b/packages/prime/tests/test_v0_compat.py @@ -0,0 +1,193 @@ +"""The frozen v0 eval surface: prime parses the argv, converts via verifiers' +compat helpers, and runs the result on the v1 CLI (field mapping is tested in +verifiers itself).""" + +import json + +import pytest +import toml +import typer +from prime_cli.utils.verifiers_v0_cli import v0_argv_to_fields +from prime_cli.verifiers_bridge import ResolvedEnvironment, run_eval_passthrough + +PLATFORM_TRANSITIONAL_TOML = """\ +model = "openai/gpt-4.1-mini" +num_examples = 5 +rollouts_per_example = 2 +save_results = true + +[[eval]] +env_args = { difficulty = "easy" } +max_retries = 4 +headers = ["X-From-Platform: 1"] +taskset = { id = "gsm8k-v1" } +harness = { id = "default" } +group_size = 2 +""" + + +class TestArgvParsing: + def test_only_explicit_flags_are_returned(self): + fields = v0_argv_to_fields( + "reverse-text", + ["--num-examples", "10", "--env-args", '{"difficulty": "hard"}', "-s"], + ) + + assert fields == { + "env_target": "reverse-text", + "num_examples": 10, + "env_args": {"difficulty": "hard"}, + "save_results": True, + } + + def test_unknown_flags_raise_system_exit(self): + with pytest.raises(SystemExit): + v0_argv_to_fields("reverse-text", ["--num-exmaples", "5"]) + + +class TestEvalDispatch: + """--save-results and transitional configs run through the conversion, not a v0 module.""" + + @pytest.fixture + def bridge_env(self, monkeypatch): + class DummyConfig: + api_key = "test-api-key" + inference_url = "https://api.pinference.ai/api/v1" + team_id = None + + class DummyPlugin: + eval_module = "verifiers.v1.cli.eval.main" + + def build_module_command(self, module, args): + return [module, *args] + + class DummyInferenceClient: + def __init__(self, timeout=None): + pass + + def retrieve_model(self, model): + return {"id": model} + + def chat_completion(self, payload, stream=False): + return {"id": "cmpl-123", "choices": []} + + commands = [] + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda ref, env_dir_path: ResolvedEnvironment( + original=ref, env_name=ref.split("/")[-1].split("@")[0], install_mode="local" + ), + ) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._run_command", + lambda command, env=None: commands.append(command), + ) + return commands + + def _converted_config_from(self, command): + assert command[0] == "verifiers.v1.cli.eval.main" + assert command[1] == "@" + return toml.load(command[2]) + + def test_save_results_argv_converts_to_v1_run(self, bridge_env): + run_eval_passthrough( + environment="reverse-text", + passthrough_args=["--num-examples", "5", "--save-results", "--disable-tui"], + skip_upload=True, + env_path=None, + ) + + config = self._converted_config_from(bridge_env[0]) + assert config["taskset"] == {"id": "reverse-text"} + assert config["num_tasks"] == 5 + assert config["rich"] is False + assert "save_results" not in config + + def test_transitional_config_without_save_results_converts(self, bridge_env, tmp_path): + config_path = tmp_path / "hosted-eval-config.toml" + config_path.write_text(PLATFORM_TRANSITIONAL_TOML) + + # the platform's raw v1 invocation: config path + --skip-upload + TUI flag + run_eval_passthrough( + environment=str(config_path), + passthrough_args=["--disable-tui"], + skip_upload=True, + env_path=None, + ) + + config = self._converted_config_from(bridge_env[0]) + assert config["taskset"] == {"id": "gsm8k-v1", "difficulty": "easy"} + assert config["num_rollouts"] == 2 + assert config["rich"] is False + # prime's run plumbing still applies to the converted config + command = bridge_env[0] + assert "--client.headers" in command + headers = json.loads(command[command.index("--client.headers") + 1]) + assert headers["X-From-Platform"] == "1" + assert "X-PI-Job-Id" in headers + + def test_debug_flag_is_accepted_as_tui_disable(self, bridge_env): + run_eval_passthrough( + environment="reverse-text", + passthrough_args=["--save-results", "--debug"], + skip_upload=True, + env_path=None, + ) + + config = self._converted_config_from(bridge_env[0]) + assert config["rich"] is False + + def test_hub_slug_taskset_is_pinned_to_installed_name(self, bridge_env, tmp_path): + config_path = tmp_path / "hosted-eval-config.toml" + config_path.write_text( + 'model = "m"\n\n[[eval]]\ntaskset = { id = "prime/some-env@0.1.2" }\n' + ) + + run_eval_passthrough( + environment=str(config_path), + passthrough_args=[], + skip_upload=True, + env_path=None, + ) + + config = self._converted_config_from(bridge_env[0]) + assert config["taskset"] == {"id": "some-env"} + + def test_typo_flags_exit_with_usage_error(self, bridge_env): + with pytest.raises(typer.Exit) as exc_info: + run_eval_passthrough( + environment="reverse-text", + passthrough_args=["--save-results", "--num-exmaples", "5"], + skip_upload=True, + env_path=None, + ) + assert exc_info.value.exit_code == 2 + + +def test_prime_eval_default_routing_forms(monkeypatch): + """`prime eval ` / `@ config` / `@config` route to the eval run (no `run` token).""" + from prime_cli.main import app + from typer.testing import CliRunner + + calls = [] + monkeypatch.setattr( + "prime_cli.commands.evals.run_eval_passthrough", + lambda **kwargs: calls.append(kwargs), + ) + + for argv, expected_environment, expected_args in [ + (["eval", "my-env", "-n", "5"], "my-env", ["-n", "5"]), + (["eval", "@", "cfg.toml"], "cfg.toml", []), + (["eval", "@cfg.toml"], "@cfg.toml", []), # the bridge strips the @ prefix + (["eval", "run", "my-env"], "my-env", []), # hidden hosted-sandbox alias + ]: + result = CliRunner().invoke(app, argv, env={"PRIME_DISABLE_VERSION_CHECK": "1"}) + assert result.exit_code == 0, result.output + call = calls.pop() + assert call["environment"] == expected_environment + assert call["passthrough_args"] == expected_args diff --git a/packages/prime/tests/test_validate.py b/packages/prime/tests/test_validate.py new file mode 100644 index 000000000..a5786ef7b --- /dev/null +++ b/packages/prime/tests/test_validate.py @@ -0,0 +1,173 @@ +"""Tests for `prime eval validate` — the wrapper around verifiers' model-free `validate`.""" + +import pytest +import typer +from prime_cli.main import app +from prime_cli.verifiers_bridge import ResolvedEnvironment, run_validate_passthrough +from prime_cli.verifiers_plugin import PrimeVerifiersPlugin +from typer.testing import CliRunner + +runner = CliRunner() + + +class DummyConfig: + api_key = "test-api-key" + inference_url = "https://api.pinference.ai/api/v1" + team_id = "team-abc" + + +class DummyPlugin: + eval_module = "verifiers.v1.cli.eval.main" + init_module = "verifiers.v1.cli.init" + validate_module = "verifiers.v1.cli.validate" + gepa_module = "verifiers.cli.commands.gepa" + + def build_module_command(self, module: str, args: list[str]) -> list[str]: + return [module, *args] + + +def _install_dummies(monkeypatch, captured: dict): + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + + def fake_run(command, env=None): + captured.update(command=command, env=env) + + monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) + + +def test_validate_help_flags_use_backend_help(monkeypatch): + def fake_help() -> None: + print("BACKEND_HELP") + + monkeypatch.setattr("prime_cli.commands.evals.print_validate_help", fake_help) + for flag in ("-h", "--help"): + result = runner.invoke( + app, ["eval", "validate", flag], env={"PRIME_DISABLE_VERSION_CHECK": "1"} + ) + assert result.exit_code == 0, result.output + assert "BACKEND_HELP" in result.output + + +def test_validate_missing_environment_shows_help(): + # no_args_is_help: bare `prime eval validate` prints help and exits 2 + result = runner.invoke(app, ["eval", "validate"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}) + assert result.exit_code == 2, result.output + assert "Usage: prime eval validate" in result.output + + +def test_validate_rejects_leading_flag_as_environment(): + # with no declared typer options, the first unknown flag is captured as the + # positional `environment` and rejected with the "must be the first argument" guard + result = runner.invoke( + app, + ["eval", "validate", "--num-tasks", "5"], + env={"PRIME_DISABLE_VERSION_CHECK": "1"}, + ) + assert result.exit_code == 2, result.output + assert "must be the first argument" in result.output + + +def test_validate_requires_api_key(monkeypatch): + class NoKeyConfig: + api_key = "" + inference_url = "" + team_id = None + + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: NoKeyConfig()) + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + + with pytest.raises(typer.Exit) as exc_info: + run_validate_passthrough(environment="gsm8k-v1", passthrough_args=[]) + + assert exc_info.value.exit_code == 1 + + +def test_validate_environment_id_resolves_and_passes_bare_name(monkeypatch, tmp_path): + captured: dict = {} + _install_dummies(monkeypatch, captured) + prepared = {} + + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda env_name, env_dir: ( + prepared.update(env=env_name, env_dir=env_dir) + or ResolvedEnvironment(original=env_name, env_name=env_name, install_mode="local") + ), + ) + + run_validate_passthrough( + environment="gsm8k-v1", + passthrough_args=["--num-tasks", "5", "--env-dir-path", str(tmp_path / "envs")], + ) + + command = captured["command"] + assert command[0] == "verifiers.v1.cli.validate" + assert command[1] == "gsm8k-v1" # bare env name, not the path + assert "--num-tasks" in command and "5" in command + assert "--env-dir-path" not in command # stripped (prime-only) + assert prepared == {"env": "gsm8k-v1", "env_dir": str(tmp_path / "envs")} + assert captured["env"]["PRIME_API_KEY"] == "test-api-key" + assert captured["env"]["PRIME_TEAM_ID"] == "team-abc" + + +def test_validate_strips_at_prefix_for_config_target(monkeypatch, tmp_path): + captured: dict = {} + _install_dummies(monkeypatch, captured) + config_path = tmp_path / "validate.toml" + config_path.write_text('[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") + + run_validate_passthrough( + environment=f"@{config_path}", + passthrough_args=["--num-tasks", "5"], + ) + + command = captured["command"] + assert command[0] == "verifiers.v1.cli.validate" + # pydantic-config reads a root config file as two tokens: `@ path` + assert command[1:3] == ["@", str(config_path)] + assert "--num-tasks" in command + + +def test_validate_at_without_path_errors(monkeypatch): + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + + result = runner.invoke(app, ["eval", "validate", "@"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}) + assert result.exit_code == 2, result.output + assert "must be followed by a config path" in result.output + + +def test_validate_module_uses_console_entrypoint_shim(monkeypatch): + monkeypatch.setattr("prime_cli.verifiers_plugin.resolve_workspace_python", lambda: "python") + plugin = PrimeVerifiersPlugin() + + command = plugin.build_module_command(plugin.validate_module, ["--help"]) + + assert command[:2] == ["python", "-c"] + assert "sys.argv[0] = 'validate'" in command[2] + assert "from verifiers.v1.cli.validate import main" in command[2] + assert command[-1] == "--help" + + +def test_sanitize_help_rewrites_validate_console_script(): + from prime_cli.verifiers_bridge import _sanitize_help_text + + # validate's prog is `validate` (not `main.py` like eval); both usage lines carry it. + raw = ( + "usage: validate [] [--runtime.type subprocess] [options] [@ file.toml]\n" + " runs each task's `validate` hook\n" + "usage: validate [-h] --taskset.id ID [OPTIONS]\n" + ) + help_text = _sanitize_help_text(raw, "verifiers.v1.cli.validate", "prime eval validate") + + assert help_text.count("Usage: prime eval validate") == 2 + assert "verifiers.v1.cli.validate" not in help_text + # the bare `usage: validate` lines are rewritten, not left behind + assert help_text.lower().count("usage: validate ") == 0 From 4f63efe836625cd8944571493d25f283430560d9 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:23:00 +0200 Subject: [PATCH 12/19] refactor: drop the frozen v0 eval surface entirely The platform's script generator moves to v1-native invocations (pinned toolchain), so prime no longer parses or converts v0 argv: - utils/verifiers_v0_cli.py deleted; transitional TOMLs convert inside verifiers at its ingestion boundary, v0 env ids ride the legacy auto-detect, and hub-slug ids in v1 configs are installed and pinned into a config copy (_pin_config_env) - hosted override flags speak the shared v1 dialect, parsed by verifiers' own EvalConfig (-n/-r/-m/--sampling.* and their aliases); endpoint/env payloads live in the config file - --save-results/--disable-tui/--debug/--sampling-args and the other v0-only flags are gone; unknown flags fail the v1 parse with a clean error --- .../prime/src/prime_cli/commands/evals.py | 161 +++------ .../src/prime_cli/utils/verifiers_v0_cli.py | 325 ------------------ .../prime/src/prime_cli/verifiers_bridge.py | 158 ++------- packages/prime/tests/test_eval_billing.py | 89 +---- packages/prime/tests/test_hosted_eval.py | 258 ++------------ packages/prime/tests/test_v0_compat.py | 193 ----------- 6 files changed, 129 insertions(+), 1055 deletions(-) delete mode 100644 packages/prime/src/prime_cli/utils/verifiers_v0_cli.py delete mode 100644 packages/prime/tests/test_v0_compat.py diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 9eb503523..32edaae5b 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -97,7 +97,6 @@ "allow_tunnel_access", "eval_name", } -HOSTED_LEGACY_UNSUPPORTED_FLAGS = {"--debug", "--tui", "-u"} HOSTED_EVAL_CONFIG_FIELD_TYPES: dict[str, tuple[type[Any], str]] = { "env_dir_path": (str, "a non-empty string"), "num_examples": (int, "an integer"), @@ -116,26 +115,6 @@ "api_key_var": (str, "a non-empty string"), "eval_name": (str, "a non-empty string"), } -HOSTED_SUPPORTED_VERIFIERS_FIELDS = { - "api_base_url", - "api_client_type", - "api_key_var", - "env_args", - "env_dir_path", - "extra_env_kwargs", - "header", - "independent_scoring", - "max_concurrent", - "verbose", - "max_retries", - "max_tokens", - "model", - "num_examples", - "rollouts_per_example", - "sampling_args", - "state_columns", - "temperature", -} HOSTED_SUPPORTED_TOML_FIELDS = { "allow_instances_access", "allow_sandbox_access", @@ -268,7 +247,7 @@ def _validate_json_object_field(merged: dict[str, Any], field_name: str) -> None def _coerce_hosted_headers(raw: dict[str, Any]) -> list[str] | None: - from ..utils.verifiers_v0_cli import build_extra_headers + from verifiers.v1.cli.eval.compat import build_extra_headers try: normalized = build_extra_headers(raw) @@ -281,61 +260,43 @@ def _coerce_hosted_headers(raw: dict[str, Any]) -> list[str] | None: return [f"{name}: {value}" for name, value in normalized.items()] -def _parse_hosted_cli_fields( - environment: str, passthrough_args: list[str], sampling_args: Optional[str] -) -> dict[str, Any]: - """The explicitly-passed hosted CLI flags as v0 fields, headers pre-coerced.""" - from ..utils.verifiers_v0_cli import build_parser, v0_argv_to_fields +def _hosted_overrides_from_flags(passthrough_args: list[str]) -> dict[str, Any]: + """Map hosted override flags onto the platform's eval_config fields. + + Hosted runs speak the same v1 flag dialect as local runs (`-n`, `-r`, `-m`, + `--sampling.*`, plus the old names via verifiers' aliases); only the fields the + caller explicitly set become overrides.""" + if not passthrough_args: + return {} + from pydantic_config import ConfigFileError + from pydantic_config import cli as pydantic_cli + from verifiers.v1.configs.eval import EvalConfig - argv = list(passthrough_args) - if sampling_args is not None: - argv.extend(["--sampling-args", sampling_args]) try: - fields = v0_argv_to_fields(environment, argv) + parsed = pydantic_cli(EvalConfig, args=list(passthrough_args), prog="prime eval --hosted") except SystemExit as exc: - raise typer.Exit(exc.code) from exc - fields.pop("env_target") - - option_names_by_dest = { - action.dest: next( - (option for option in action.option_strings if option.startswith("--")), - action.option_strings[0], - ) - for action in build_parser()._actions - if action.option_strings - } - unsupported_flags = [ - option_names_by_dest[dest] - for dest in fields - if dest not in HOSTED_SUPPORTED_VERIFIERS_FIELDS - ] - if unsupported_flags: - console.print( - "[red]Error:[/red] hosted eval CLI does not support: " - + ", ".join(f"`{flag}`" for flag in unsupported_flags) - ) - raise typer.Exit(1) - - if "header" in fields: - fields["headers"] = _coerce_hosted_headers({"header": fields.pop("header")}) - return fields - - -def _reject_legacy_unsupported_hosted_flags(passthrough_args: list[str]) -> None: - unsupported_flags = [] - for arg in passthrough_args: - flag = arg.split("=", 1)[0] - if flag in HOSTED_LEGACY_UNSUPPORTED_FLAGS and flag not in unsupported_flags: - unsupported_flags.append(flag) - - if not unsupported_flags: - return - - console.print( - "[red]Error:[/red] hosted eval CLI does not support: " - + ", ".join(f"`{flag}`" for flag in unsupported_flags) - ) - raise typer.Exit(1) + raise typer.Exit(exc.code if isinstance(exc.code, int) else 2) from exc + except ConfigFileError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + + overrides: dict[str, Any] = {} + provided = parsed.model_fields_set + if "num_tasks" in provided: + # v1's unset num_tasks means "all"; the platform spells that -1 + overrides["num_examples"] = -1 if parsed.num_tasks is None else parsed.num_tasks + if "num_rollouts" in provided: + overrides["rollouts_per_example"] = parsed.num_rollouts + if "model" in provided: + overrides["model"] = parsed.model + if "max_concurrent" in provided: + overrides["max_concurrent"] = parsed.max_concurrent + if "verbose" in provided: + overrides["verbose"] = parsed.verbose + sampling = parsed.sampling.model_dump(exclude_none=True) + if sampling: + overrides["sampling_args"] = sampling + return overrides def _freeze_json_value(value: Any) -> Any: @@ -430,7 +391,7 @@ def _resolve_hosted_config_model(raw_config: dict[str, Any], config_path: Path) def _validate_single_hosted_eval_config( merged: dict[str, Any], config_path: Path ) -> dict[str, Any]: - from ..utils.verifiers_v0_cli import merge_sampling_args + from verifiers.v1.cli.eval.compat import merge_sampling_args unsupported_fields = sorted( field_name for field_name in merged if field_name not in HOSTED_SUPPORTED_TOML_FIELDS @@ -1537,14 +1498,6 @@ def run_eval_cmd( "--custom-secrets", help='Custom secrets for hosted eval as JSON (e.g. \'{"API_KEY":"xxx"}\')', ), - sampling_args: Optional[str] = typer.Option( - None, - "--sampling-args", - help=( - "Sampling args as JSON for local or hosted evals. " - 'Example: {"temperature": 0.7, "extra_body": {"provider": {"order": ["azure"]}}}' - ), - ), eval_name: Optional[str] = typer.Option( None, "--eval-name", @@ -1591,15 +1544,6 @@ def run_eval_cmd( local_passthrough_args = list(passthrough_args) if not hosted: - legacy_eval = any(arg in ("--save-results", "-s") for arg in local_passthrough_args) - if sampling_args is not None and legacy_eval: - local_passthrough_args.extend(["--sampling-args", sampling_args]) - elif sampling_args is not None: - console.print( - "[red]Error:[/red] local v1 evals use --sampling.* options " - "(for example, --sampling.temperature 0.7)" - ) - raise typer.Exit(2) hosted_only_args = { "--follow": follow, "--poll-interval": poll_interval_was_provided, @@ -1619,9 +1563,9 @@ def run_eval_cmd( raise typer.Exit(1) if hosted: - _reject_legacy_unsupported_hosted_flags(passthrough_args) - cli_fields = _parse_hosted_cli_fields(environment, passthrough_args, sampling_args) - env_dir_path = cli_fields.get("env_dir_path") + # run knobs come from the config file or the shared v1 flag dialect; + # everything endpoint/env-specific belongs in the config file + overrides = _hosted_overrides_from_flags(passthrough_args) hosted_target_configs: list[dict[str, Any]] = [] if _is_config_target(environment): @@ -1639,41 +1583,28 @@ def run_eval_cmd( effective_targets: list[dict[str, Any]] = [] for target_config in hosted_target_configs: - merged = {**target_config, **cli_fields} # explicit CLI flags win over config + merged = {**target_config, **overrides} # explicit CLI flags win over config try: num_examples = int(merged.get("num_examples", HOSTED_RUN_DEFAULT_NUM_EXAMPLES)) rollouts_per_example = int( merged.get("rollouts_per_example", HOSTED_RUN_DEFAULT_ROLLOUTS_PER_EXAMPLE) ) except (TypeError, ValueError) as exc: - console.print( - "[red]Error:[/red] --num-examples and --rollouts-per-example must be integers" - ) + console.print("[red]Error:[/red] --num-tasks and --num-rollouts must be integers") raise typer.Exit(1) from exc if num_examples < -1 or rollouts_per_example < 1: console.print( - "[red]Error:[/red] --num-examples must be >= -1 and " - "--rollouts-per-example must be >= 1" + "[red]Error:[/red] --num-tasks must be >= -1 and --num-rollouts must be >= 1" ) raise typer.Exit(1) - base_sampling_args = merged.get("sampling_args") - if base_sampling_args is not None and not isinstance(base_sampling_args, dict): + effective_sampling_args = merged.get("sampling_args") + if effective_sampling_args is not None and not isinstance( + effective_sampling_args, dict + ): console.print("[red]Error:[/red] `sampling_args` must be a JSON object") raise typer.Exit(1) - from ..utils.verifiers_v0_cli import merge_sampling_args - - effective_sampling_args = ( - merge_sampling_args( - base_sampling_args, - max_tokens=cli_fields.get("max_tokens"), - temperature=cli_fields.get("temperature"), - # an explicit --sampling-args wins over --max-tokens/--temperature - prefer_existing_keys="sampling_args" in cli_fields, - ) - or None - ) effective_targets.append( { diff --git a/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py b/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py deleted file mode 100644 index c0554c11f..000000000 --- a/packages/prime/src/prime_cli/utils/verifiers_v0_cli.py +++ /dev/null @@ -1,325 +0,0 @@ -"""The frozen v0 verifiers eval CLI argv surface, vendored for hosted evals. - -Hosted-eval sandboxes still emit the classic v0 `vf-eval` argv, so prime must parse -and validate that argument surface — to build hosted requests, and to convert local -runs onto the v1 CLI. Verifiers has removed the v0 CLI itself; the frozen parser -lives here (vendored from verifiers v0.1.15 `verifiers/scripts/eval.py`) while the -config-level compat helpers live in `verifiers.v1.cli.eval.compat`. -""" - -import argparse -import json -from typing import Any - -from verifiers.v1.cli.eval.compat import ( # noqa: F401 (re-exported for callers) - PROVIDER_CONFIGS, - build_extra_headers, - merge_sampling_args, -) - -DEFAULT_MODEL = "openai/gpt-4.1-mini" -DEFAULT_ENV_DIR_PATH = "./environments" -DEFAULT_ENDPOINTS_PATH = "./configs/endpoints.toml" -DEFAULT_NUM_EXAMPLES = 5 -DEFAULT_ROLLOUTS_PER_EXAMPLE = 3 -DEFAULT_MAX_CONCURRENT = 32 -DEFAULT_CLIENT_TYPE = "openai_chat_completions" -DEFAULT_PROVIDER = "prime" - - -def v0_argv_to_fields(environment: str, passthrough_args: list[str]) -> dict[str, Any]: - """Parse a frozen-surface argv into the explicitly-provided v0 fields. - - Returns only flags the caller actually passed (defaults suppressed), plus the - positional target under ``env_target``. Raises SystemExit on unknown flags, - exactly like the v0 CLI did. - """ - parser = build_parser() - for action in parser._actions: - if action.option_strings: - action.default = argparse.SUPPRESS - namespace = parser.parse_args([environment, *passthrough_args]) - fields = {k: v for k, v in vars(namespace).items() if k != "env_id_or_config"} - fields["env_target"] = namespace.env_id_or_config - return fields - - -def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser() - parser.add_argument( - "env_id_or_config", - type=str, - default="gsm8k", - help="Environment module name or path to TOML config file.", - ) - parser.add_argument( - "--env-args", - "-a", - type=json.loads, - default={}, - help='Environment module arguments as JSON object (e.g., \'{"key": "value", "num": 42}\')', - ) - parser.add_argument( - "--env-dir-path", - type=str, - default=DEFAULT_ENV_DIR_PATH, - help="Path to environments directory", - ) - parser.add_argument( - "--provider", - "-p", - type=str, - default=None, - choices=list(PROVIDER_CONFIGS.keys()), - help=( - "Inference provider shorthand. Resolves --api-base-url and --api-key-var " - "automatically. Explicit --api-base-url / --api-key-var take precedence. " - "Overrides endpoint registry when model is in registry. " - "Falls back to 'prime' when model is not in registry." - ), - ) - parser.add_argument( - "--endpoints-path", - "-e", - type=str, - default=DEFAULT_ENDPOINTS_PATH, - help="Path to API endpoints TOML registry", - ) - parser.add_argument( - "--model", - "-m", - type=str, - default=DEFAULT_MODEL, - help="Name of model to evaluate", - ) - parser.add_argument( - "--api-client-type", - type=str, - default=None, - help=( - "Which client type to use ('openai_completions', 'openai_chat_completions', " - "'openai_chat_completions_token', 'openai_responses', 'renderer', " - "'anthropic_messages', 'nemorl_chat_completions')" - ), - choices=[ - "openai_completions", - "openai_chat_completions", - "openai_chat_completions_token", - "openai_responses", - "renderer", - "anthropic_messages", - "nemorl_chat_completions", - ], - ) - parser.add_argument( - "--api-key-var", - "-k", - type=str, - default=None, - help="Environment variable name for API key (overrides --provider)", - ) - parser.add_argument( - "--api-base-url", - "-b", - type=str, - default=None, - help="Base URL for API (overrides --provider)", - ) - parser.add_argument( - "--header", - action="append", - default=None, - help="Extra HTTP header to pass to inference API. 'Name: Value'. Repeatable.", - ) - parser.add_argument( - "--header-from-state", - action="append", - default=None, - help=( - "Per-request HTTP header whose value is read from the rollout state. " - "'Name: state_key' (e.g. 'X-Session-ID: trajectory_id'). Repeatable. " - "Defaults to X-Session-ID=trajectory_id if unset." - ), - ) - parser.add_argument( - "--num-examples", - "-n", - type=int, - default=None, - help="Number of examples to evaluate", - ) - parser.add_argument( - "--rollouts-per-example", - "-r", - type=int, - default=None, - help="Number of rollouts per example", - ) - parser.add_argument( - "--shuffle", - default=False, - action="store_true", - help="Shuffle the evaluation dataset before selecting examples", - ) - parser.add_argument( - "--shuffle-seed", - type=int, - default=None, - help="Seed for --shuffle. Defaults to 0 when --shuffle is enabled.", - ) - parser.add_argument( - "--max-concurrent", - "-c", - type=int, - default=DEFAULT_MAX_CONCURRENT, - help="Maximum number of concurrent requests", - ) - parser.add_argument( - "--max-tokens", - "-t", - type=int, - default=None, - help="Maximum number of tokens to generate (unset to use model default)", - ) - parser.add_argument( - "--temperature", "-T", type=float, default=None, help="Temperature for sampling" - ) - parser.add_argument( - "--sampling-args", - "-S", - type=json.loads, - default=None, - help=( - "Sampling arguments as JSON object. Keys here override --max-tokens/--temperature. " - 'Example: \'{"enable_thinking": false, "max_tokens": 256}\'' - ), - ) - parser.add_argument( - "--output-dir", - "-o", - type=str, - default=None, - help="Custom output directory for evaluation results and logs", - ) - parser.add_argument( - "--verbose", "-v", default=False, action="store_true", help="Verbose output" - ) - parser.add_argument( - "--no-interleave-scoring", - "-N", - default=False, - action="store_true", - help="Disable interleaving of scoring", - ) - parser.add_argument( - "--state-columns", - "-C", - type=lambda t: [s.strip() for s in t.split(",")], - default=[], - help="Comma-separated list of state columns to save (e.g., 'turn,timing')", - ) - parser.add_argument( - "--save-results", - "-s", - default=False, - action="store_true", - help="Save results to disk", - ) - parser.add_argument( - "--resume", - "-R", - nargs="?", - const=True, - default=None, - metavar="PATH", - help=( - "Resume from a previous run. Optionally provide a PATH; " - "if omitted, auto-detect the latest incomplete matching run." - ), - ) - parser.add_argument( - "--independent-scoring", - "-i", - default=False, - action="store_true", - help="Score each rollout individually instead of scoring by group", - ) - parser.add_argument( - "--save-to-hf-hub", - "-H", - default=False, - action="store_true", - help="Save dataset to Hugging Face Hub", - ) - parser.add_argument( - "--hf-hub-dataset-name", - "-D", - type=str, - default="", - help="Name of dataset to save to Hugging Face Hub", - ) - parser.add_argument( - "--extra-env-kwargs", - "-x", - type=json.loads, - default={}, - help=( - 'Extra environment as JSON object (e.g., \'{"key": "value", "num": 42}\'). ' - "Passed to environment constructor." - ), - ) - parser.add_argument( - "--timeout", - type=float, - default=None, - help=( - "Per-rollout wall-clock timeout in seconds. " - "Overrides timeout_seconds in --extra-env-kwargs." - ), - ) - parser.add_argument( - "--fullscreen", - "-f", - default=False, - action="store_true", - help="Use fullscreen (alternate-screen) mode for the Rich live evaluation display", - ) - parser.add_argument( - "--disable-tui", - "-d", - default=False, - action="store_true", - help="Disable Rich display; use normal logging and tqdm progress instead", - ) - parser.add_argument( - "--max-retries", - type=int, - default=3, - help="Max retries for transient infrastructure errors (default: 3)", - ) - parser.add_argument( - "--disable-env-server", - default=False, - action="store_true", - help="Do not start env servers when evaluating environments", - ) - parser.add_argument( - "--num-workers", - "-w", - default="auto", - help='Number of env server worker processes ("auto" = concurrency // 256, or an integer)', - ) - parser.add_argument( - "--abbreviated-summary", - "-A", - default=False, - action="store_true", - help="Abbreviated summary: show settings and stats only, skip example prompts/completions", - ) - parser.add_argument( - "--heartbeat-url", - type=str, - default=None, - help="Heartbeat URL for uptime monitoring", - ) - return parser diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 7e1a3330c..54977f347 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -8,7 +8,7 @@ import subprocess import sys import uuid -from dataclasses import dataclass, replace +from dataclasses import dataclass from datetime import datetime from pathlib import Path from typing import Optional @@ -158,7 +158,6 @@ def _write_help(text: str) -> None: def _append_eval_options(help_text: str) -> str: extra_lines = [ " --skip-upload Skip uploading evaluation results to the platform.", - " --disable-tui Disable the live display (alias for --rich false).", " --env-path PATH Explicit path for upstream environment metadata.", " --hosted Run the evaluation on the platform instead of locally.", " --poll-interval FLOAT Polling interval in seconds for hosted evaluations.", @@ -941,19 +940,11 @@ def run_eval_passthrough( ) raise typer.Exit(1) - args = list(passthrough_args) - tui_disabled = _pop_tui_flags(args) - - # Hosted-eval sandboxes still emit the frozen v0 CLI surface (marked by - # --save-results); convert it onto the v1 CLI, which always saves results. - if _has_flag(args, "--save-results", "-s"): - run = _run_converted_v0_eval(environment, args, config, tui_disabled=tui_disabled) + resume_dir = _parse_value_option(passthrough_args, "--resume", None) + if resume_dir is not None: + run = _resume_v1_eval(resume_dir, passthrough_args, config) else: - resume_dir = _parse_value_option(args, "--resume", None) - if resume_dir is not None: - run = _resume_v1_eval(resume_dir, args, config) - else: - run = _run_v1_eval(environment, args, config, tui_disabled=tui_disabled) + run = _run_v1_eval(environment, passthrough_args, config) _upload_v1_results(run, skip_upload=skip_upload, env_path=env_path) @@ -993,104 +984,35 @@ def run_validate_passthrough(environment: str, passthrough_args: list[str]) -> N _run_command(plugin.build_module_command(plugin.validate_module, [*run_args, *args]), env=env) -def _pop_tui_flags(args: list[str]) -> bool: - """Remove the v0 TUI flags hosted-eval scripts append; v1 maps them to --rich false.""" - found = False - for flag in ("--disable-tui", "--debug"): - while flag in args: - args.remove(flag) - found = True - return found - - -def _load_transitional_fields(config_path: Path) -> dict: - from verifiers.v1.cli.eval.compat import transitional_config_to_fields - - try: - return transitional_config_to_fields(config_path) - except ValueError as exc: - console.print(f"[red]Error:[/red] {exc}") - raise typer.Exit(2) from exc - - -def _write_converted_v1_config( - fields: dict, *, tui_disabled: bool -) -> tuple[Path, ResolvedEnvironment]: - """Turn flattened v0 fields into a v1 config file with a locally importable env id.""" - from verifiers.v1.cli.eval.compat import ( - build_v1_eval_config, - write_converted_eval_config, - ) +def _pin_config_env( + config_data: dict, config_path: str, env_dir_path: str +) -> tuple[str, Optional[ResolvedEnvironment]]: + """Install a config's hub env ref and pin the locally importable name into a copy. - env_dir_path = str(fields.pop("env_dir_path", None) or DEFAULT_ENV_DIR_PATH) - taskset = fields.get("taskset") + The v1 CLI accepts only local ids; prime owns acquisition, so `owner/name[@version]` + refs are installed here and the config is rewritten before verifiers parses it.""" + taskset = config_data.get("taskset") taskset_id = taskset.get("id") if isinstance(taskset, dict) else None - env_ref = taskset_id or fields.get("id") + env_ref = taskset_id or config_data.get("id") if not (isinstance(env_ref, str) and env_ref): - console.print("[red]Error:[/red] eval config requires an env_id or taskset.id") - raise typer.Exit(2) + return config_path, None - # install hub refs and pin the locally importable name into the config resolved = _prepare_v1_environment(env_ref, env_dir_path) - if taskset_id: - fields["taskset"] = {**taskset, "id": resolved.env_name} - else: - fields["id"] = resolved.env_name - - try: - v1_config, warnings = build_v1_eval_config(fields, tui_disabled=tui_disabled) - except ValueError as exc: - console.print(f"[red]Error:[/red] {exc}") - raise typer.Exit(2) from exc - for warning in warnings: - console.print(f"[yellow]Warning:[/yellow] {warning}") - - if resolved.env_display_id: - headers = v1_config.setdefault("client", {}).setdefault("headers", {}) - headers.setdefault(INTERNAL_ENV_DISPLAY_HEADER, resolved.env_display_id) - config_path = write_converted_eval_config( - v1_config, header_comment="converted from the v0 eval surface by prime" - ) - console.print(f"[dim]Converted v0 eval invocation to {config_path}[/dim]") - return config_path, resolved + if resolved.env_name == env_ref: + return config_path, resolved + from verifiers.v1.cli.eval.compat import write_converted_eval_config -def _run_converted_v0_eval( - environment: str, - passthrough_args: list[str], - config: Config, - *, - tui_disabled: bool, -) -> V1EvalRun: - """Run a frozen v0 invocation (hosted argv and/or a transitional TOML) on the v1 CLI. - - Classic env ids route through verifiers' legacy bridge automatically, so the - converted config never has to tag the environment generation.""" - from .utils.verifiers_v0_cli import v0_argv_to_fields - - try: - argv_fields = v0_argv_to_fields(environment, passthrough_args) - except SystemExit as exc: - raise typer.Exit(exc.code if isinstance(exc.code, int) else 2) from exc - target = str(argv_fields.pop("env_target")) - - fields: dict = {} - is_config = _is_config_target(target) - if is_config: - fields = _load_transitional_fields(Path(target)) + pinned = dict(config_data) + if taskset_id: + pinned["taskset"] = {**taskset, "id": resolved.env_name} else: - # bare env id: verifiers auto-detects v0 envs given as the taskset id - fields["taskset"] = {"id": target} - fields.update(argv_fields) - - config_path, resolved = _write_converted_v1_config(fields, tui_disabled=tui_disabled) - run = _run_v1_eval(str(config_path), [], config) - if not is_config: - # keep bare-env upload attribution: this run is config-driven only as plumbing - run = replace( - run, is_config=False, resolved_env=resolved, upstream_slug=resolved.upstream_slug - ) - return run + pinned["id"] = resolved.env_name + pinned_path = write_converted_eval_config( + pinned, header_comment=f"hub env pinned to local install by prime ({config_path})" + ) + console.print(f"[dim]Pinned {env_ref} to local install in {pinned_path}[/dim]") + return str(pinned_path), resolved def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config) -> V1EvalRun: @@ -1122,11 +1044,12 @@ def _run_v1_eval( environment: str, passthrough_args: list[str], config: Config, - *, - tui_disabled: bool = False, ) -> V1EvalRun: """Prepare and run a fresh v1 eval: fill in prime's model/base-url/output-dir defaults, - make the environment importable, and tag the run with a job id header.""" + make the environment importable, and tag the run with a job id header. + + Legacy (v0) inputs need no handling here: verifiers auto-detects v0 env ids and + converts transitional configs at its own ingestion boundary.""" target = environment.removeprefix("@") is_config = _is_config_target(target) args = list(passthrough_args) @@ -1136,14 +1059,6 @@ def _run_v1_eval( env["PRIME_TEAM_ID"] = config.team_id config_data: dict = toml.load(target) if is_config else {} - if "env_id" in config_data or "eval" in config_data: - # a transitional/hosted v0 config (`env_id` / `[[eval]]`): convert it in place - fields = _load_transitional_fields(Path(target)) - target = str(_write_converted_v1_config(fields, tui_disabled=tui_disabled)[0]) - tui_disabled = False # the converted config already sets rich = false - config_data = toml.load(target) - if tui_disabled: - args.extend(["--rich", "false"]) config_model = config_data.get("model") cli_model = _parse_value_option(args, "--model", "-m") model = cli_model or config_model or DEFAULT_MODEL @@ -1182,16 +1097,9 @@ def _run_v1_eval( upstream_slug: Optional[str] = None if is_config: - taskset = config_data.get("taskset") - env_ref = taskset.get("id") if isinstance(taskset, dict) else None - if not (isinstance(env_ref, str) and env_ref): - # v1's legacy field: a top-level `id` runs a v0 env through the bridge - env_ref = config_data.get("id") - if isinstance(env_ref, str) and env_ref: - _prepare_v1_environment(env_ref, env_dir_path) - job_target = _env_name_from_reference(env_ref) - else: - job_target = Path(target).stem + # install hub refs and pin the local name into a config copy before verifiers parses + target, resolved_env = _pin_config_env(config_data, target, env_dir_path) + job_target = resolved_env.env_name if resolved_env else Path(target).stem # pydantic-config only reads a root config file as two tokens: `@ path` run_args = ["@", target] else: diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index a2b86b5f4..94f62a333 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -212,76 +212,6 @@ def __init__(self, timeout=None): assert captured["env"]["PRIME_API_KEY"] == "test-api-key" -@pytest.mark.parametrize("save_flag", ["--save-results", "-s"]) -def test_eval_run_legacy_save_results_converts_to_v1(monkeypatch, save_flag): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda *_args: ResolvedEnvironment( - original="legacy-env", env_name="legacy-env", install_mode="local" - ), - ) - captured = {} - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: captured.update(command=command, env=env), - ) - - run_eval_passthrough( - environment="legacy-env", - passthrough_args=[ - save_flag, - "--debug", - "--num-examples", - "1", - "--rollouts-per-example", - "2", - ], - skip_upload=True, - env_path=None, - ) - - # the frozen v0 surface now runs converted on the v1 entrypoint - assert captured["command"][0] == "verifiers.v1.cli.eval.main" - assert captured["command"][1] == "@" - converted = toml.load(captured["command"][2]) - assert converted["taskset"] == {"id": "legacy-env"} - assert converted["num_tasks"] == 1 - assert converted["num_rollouts"] == 2 - assert converted["rich"] is False # --debug means "no live display" - assert "--client.headers" in captured["command"] - - -def test_eval_run_v0_resume_is_rejected_with_guidance(monkeypatch): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda *_args: ResolvedEnvironment( - original="legacy-env", env_name="legacy-env", install_mode="local" - ), - ) - - with pytest.raises(typer.Exit) as exc_info: - run_eval_passthrough( - environment="legacy-env", - passthrough_args=["-s", "--resume", "/tmp/legacy-results.jsonl"], - skip_upload=True, - env_path=None, - ) - - assert cast(typer.Exit, exc_info.value).exit_code == 2 - - def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): monkeypatch.setattr( "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() @@ -533,6 +463,11 @@ def test_eval_config_uses_v1_taskset(monkeypatch, tmp_path, prefix): def fake_prepare(env_reference, env_dir_path): prepared.append((env_reference, env_dir_path)) + return ResolvedEnvironment( + original=env_reference, + env_name=env_reference.split("/")[-1], + install_mode="hub", + ) def fake_run_command(command, env=None): commands.append(command) @@ -549,8 +484,11 @@ def fake_run_command(command, env=None): assert prepared == [("primeintellect/wordle", "./environments")] assert commands - # pydantic-config only accepts a root config file as two tokens: `@ path` - assert commands[0][1:3] == ["@", str(config_path)] + # pydantic-config only accepts a root config file as two tokens: `@ path`; + # the hub slug is installed and pinned to the local name in a config copy + assert commands[0][1] == "@" + assert commands[0][2] != str(config_path) + assert toml.load(commands[0][2])["taskset"]["id"] == "wordle" header_idx = commands[0].index("--client.headers") headers = json.loads(commands[0][header_idx + 1]) assert headers["X-PI-Job-Id"].startswith("wordle_openai_gpt_4.1_mini_") @@ -613,7 +551,12 @@ def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): monkeypatch.setattr( "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None ) - monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_v1_environment", lambda *_: None) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda *_: ResolvedEnvironment( + original="gsm8k-v1", env_name="gsm8k-v1", install_mode="local" + ), + ) output_dir = tmp_path / "configured-output" config_path = tmp_path / "eval.toml" diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index a2d7d8581..09a8d9853 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -160,11 +160,7 @@ def test_eval_run_hosted_passes_runtime_args_from_cli(monkeypatch): def fake_run_hosted_evaluation(config, environment_ids=None): captured["max_concurrent"] = config.max_concurrent - captured["max_retries"] = config.max_retries - captured["state_columns"] = config.state_columns - captured["independent_scoring"] = config.independent_scoring captured["verbose"] = config.verbose - captured["headers"] = config.headers captured["sampling_args"] = config.sampling_args return {"evaluation_id": "eval-123"} @@ -182,17 +178,10 @@ def fake_run_hosted_evaluation(config, environment_ids=None): "--hosted", "--max-concurrent", "100", - "--max-retries", - "3", - "--state-columns", - "turn,timing", - "--independent-scoring", - "--verbose", - "--header", - "X-Test: one", - "--max-tokens", + "-v", + "--sampling.max-tokens", "4096", - "--temperature", + "--sampling.temperature", "0.2", ], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, @@ -201,17 +190,23 @@ def fake_run_hosted_evaluation(config, environment_ids=None): assert result.exit_code == 0, result.output assert captured == { "max_concurrent": 100, - "max_retries": 3, - "state_columns": ["turn", "timing"], - "independent_scoring": True, "verbose": True, - "headers": ["X-Test: one"], "sampling_args": {"max_tokens": 4096, "temperature": 0.2}, } -def test_eval_run_hosted_passes_api_base_url_and_key_var(monkeypatch): +def test_eval_run_hosted_passes_api_base_url_and_key_var(monkeypatch, tmp_path): captured = {} + config_path = tmp_path / "eval.toml" + config_path.write_text( + """ +api_base_url = "https://api.openai.com/v1" +api_key_var = "OPENAI_API_KEY" + +[[eval]] +env_id = "gsm8k" +""".strip() + ) monkeypatch.setattr( "prime_cli.commands.evals._resolve_hosted_environment", @@ -233,18 +228,7 @@ def fake_run_hosted_evaluation(config, environment_ids=None): result = runner.invoke( app, - [ - "eval", - "run", - "primeintellect/gsm8k", - "--hosted", - "-m", - "openai/gpt-4.1-mini", - "-b", - "https://api.openai.com/v1", - "-k", - "OPENAI_API_KEY", - ], + ["eval", "run", str(config_path), "--hosted", "-m", "openai/gpt-4.1-mini"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) @@ -289,8 +273,17 @@ def fake_run_hosted_evaluation(config, environment_ids=None): assert captured["allow_tunnel_access"] is True -def test_eval_run_hosted_passes_extra_env_kwargs(monkeypatch): +def test_eval_run_hosted_passes_extra_env_kwargs(monkeypatch, tmp_path): captured = {} + config_path = tmp_path / "eval.toml" + config_path.write_text( + """ +extra_env_kwargs = { task_library = "ronig", keep_remote_artifacts = true } + +[[eval]] +env_id = "gsm8k" +""".strip() + ) monkeypatch.setattr( "prime_cli.commands.evals._resolve_hosted_environment", @@ -311,16 +304,7 @@ def fake_run_hosted_evaluation(config, environment_ids=None): result = runner.invoke( app, - [ - "eval", - "run", - "primeintellect/gsm8k", - "--hosted", - "-m", - "openai/gpt-4.1-mini", - "-x", - '{"task_library":"ronig","keep_remote_artifacts":true}', - ], + ["eval", "run", str(config_path), "--hosted", "-m", "openai/gpt-4.1-mini"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) @@ -749,6 +733,7 @@ def test_eval_run_hosted_cli_overrides_supported_toml_fields(monkeypatch, tmp_pa [[eval]] env_id = "gsm8k" env_args = { split = "test" } +extra_env_kwargs = { task_library = "ronig", keep_remote_artifacts = true } """.strip() ) @@ -789,14 +774,10 @@ def fake_run_hosted_evaluation(config, environment_ids=None): "3", "-r", "4", - "--env-args", - '{"split":"validation"}', "--timeout-minutes", "240", - "--sampling-args", - '{"temperature":0.2,"extra_body":{"provider":{"order":["azure"],"allow_fallbacks":false,"require_parameters":true}}}', - "--extra-env-kwargs", - '{"task_library":"ronig","keep_remote_artifacts":true}', + "--sampling.temperature", + "0.2", "--eval-name", "from cli", ], @@ -809,21 +790,12 @@ def fake_run_hosted_evaluation(config, environment_ids=None): "inference_model": "anthropic/claude-sonnet-4", "num_examples": 3, "rollouts_per_example": 4, - "env_args": {"split": "validation"}, + "env_args": {"split": "test"}, "timeout_minutes": 240, "allow_sandbox_access": True, "allow_instances_access": True, "allow_tunnel_access": True, - "sampling_args": { - "temperature": 0.2, - "extra_body": { - "provider": { - "order": ["azure"], - "allow_fallbacks": False, - "require_parameters": True, - } - }, - }, + "sampling_args": {"temperature": 0.2}, "extra_env_kwargs": { "task_library": "ronig", "keep_remote_artifacts": True, @@ -1133,52 +1105,6 @@ def test_eval_run_hosted_rejects_explicit_unsupported_toml_fields( assert f"`{expected_field}`" in result.output -def test_eval_run_hosted_toml_preserves_cli_env_dir_path(monkeypatch, tmp_path): - captured = {} - config_path = tmp_path / "eval.toml" - config_path.write_text( - """ -[[eval]] -env_id = "gsm8k" -""".strip() - ) - - def fake_resolve(environment, env_dir_path=None, env_path=None): - captured["environment"] = environment - captured["env_dir_path"] = env_dir_path - captured["env_path"] = env_path - return ("primeintellect/gsm8k", "env-123") - - def fake_run_hosted_evaluation(config, environment_ids=None): - return {"evaluation_id": "eval-123"} - - monkeypatch.setattr("prime_cli.commands.evals._resolve_hosted_environment", fake_resolve) - monkeypatch.setattr( - "prime_cli.commands.evals._create_hosted_evaluations", - fake_run_hosted_evaluation, - ) - - result = runner.invoke( - app, - [ - "eval", - "run", - str(config_path), - "--hosted", - "--env-dir-path", - "/tmp/custom-envs", - ], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured == { - "environment": "gsm8k", - "env_dir_path": "/tmp/custom-envs", - "env_path": None, - } - - def test_hosted_eval_config_accepts_id_alias(tmp_path): config_path = tmp_path / "eval.toml" config_path.write_text( @@ -1422,130 +1348,14 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa } -@pytest.mark.parametrize( - ("extra_args", "expected_flag"), - [ - (["--provider", "openai"], "--provider"), - (["--endpoints-path", "./configs/endpoints.toml"], "--endpoints-path"), - (["--output-dir", "/tmp/results"], "--output-dir"), - (["--no-interleave-scoring"], "--no-interleave-scoring"), - (["--save-results"], "--save-results"), - (["--resume", "/tmp/results.json"], "--resume"), - (["--save-to-hf-hub"], "--save-to-hf-hub"), - (["--hf-hub-dataset-name", "dataset-name"], "--hf-hub-dataset-name"), - (["--tui"], "--tui"), - (["--debug"], "--debug"), - (["--disable-env-server"], "--disable-env-server"), - (["--num-workers", "auto"], "--num-workers"), - (["--abbreviated-summary"], "--abbreviated-summary"), - (["--heartbeat-url", "https://example.com/heartbeat"], "--heartbeat-url"), - ], -) -def test_eval_run_hosted_rejects_unsupported_passthrough_flags(extra_args, expected_flag): - result = runner.invoke( - app, - ["eval", "run", "gsm8k", "--hosted", *extra_args], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 1 - assert "hosted eval CLI does not support" in result.output - assert f"`{expected_flag}`" in result.output - - -def test_eval_run_hosted_accepts_negative_num_examples_value(monkeypatch): - captured = {} - - def fake_create_hosted_evaluations(config, environment_ids=None): - captured["num_examples"] = config.num_examples - return {"evaluation_id": "eval-123"} - - monkeypatch.setattr( - "prime_cli.commands.evals._create_hosted_evaluations", - fake_create_hosted_evaluations, - ) - monkeypatch.setattr( - "prime_cli.commands.evals._resolve_hosted_environment", - lambda environment, env_dir_path=None, env_path=None: ("primeintellect/gsm8k", "env-123"), - ) - - result = runner.invoke( - app, - ["eval", "run", "gsm8k", "--hosted", "--num-examples", "-1"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured["num_examples"] == -1 - - -def test_eval_run_rejects_hosted_only_flags_without_hosted(): +def test_eval_run_hosted_rejects_v0_only_flags(): result = runner.invoke( app, - ["eval", "run", "gsm8k", "--follow"], + ["eval", "run", "gsm8k", "--hosted", "--state-columns", "turn,timing"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) - assert result.exit_code == 1 - assert "hosted-only options require `--hosted`" in result.output - -def test_eval_run_rejects_explicit_poll_interval_without_hosted(): - result = runner.invoke( - app, - ["eval", "run", "gsm8k", "--poll-interval", "10"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - assert result.exit_code == 1 - assert "hosted-only options require `--hosted`" in result.output - - -def test_eval_run_rejects_tunnel_access_without_hosted(): - result = runner.invoke( - app, - ["eval", "run", "gsm8k", "--allow-tunnel-access"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - assert result.exit_code == 1 - assert "hosted-only options require `--hosted`" in result.output - - -def test_eval_run_hosted_passes_env_dir_path_to_resolver(monkeypatch): - captured = {} - - def fake_resolve(environment, env_dir_path=None, env_path=None): - captured["environment"] = environment - captured["env_dir_path"] = env_dir_path - captured["env_path"] = env_path - return ("primeintellect/gsm8k", "env-123") - - def fake_run_hosted_evaluation(config, environment_ids=None): - return {"evaluation_id": "eval-123"} - - monkeypatch.setattr("prime_cli.commands.evals._resolve_hosted_environment", fake_resolve) - monkeypatch.setattr( - "prime_cli.commands.evals._create_hosted_evaluations", - fake_run_hosted_evaluation, - ) - - result = runner.invoke( - app, - [ - "eval", - "run", - "gsm8k", - "--hosted", - "--env-dir-path", - "/tmp/custom-envs", - ], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured == { - "environment": "gsm8k", - "env_dir_path": "/tmp/custom-envs", - "env_path": None, - } + assert result.exit_code == 2 def test_eval_run_hosted_passes_env_path_to_resolver(monkeypatch): diff --git a/packages/prime/tests/test_v0_compat.py b/packages/prime/tests/test_v0_compat.py deleted file mode 100644 index 765eeac18..000000000 --- a/packages/prime/tests/test_v0_compat.py +++ /dev/null @@ -1,193 +0,0 @@ -"""The frozen v0 eval surface: prime parses the argv, converts via verifiers' -compat helpers, and runs the result on the v1 CLI (field mapping is tested in -verifiers itself).""" - -import json - -import pytest -import toml -import typer -from prime_cli.utils.verifiers_v0_cli import v0_argv_to_fields -from prime_cli.verifiers_bridge import ResolvedEnvironment, run_eval_passthrough - -PLATFORM_TRANSITIONAL_TOML = """\ -model = "openai/gpt-4.1-mini" -num_examples = 5 -rollouts_per_example = 2 -save_results = true - -[[eval]] -env_args = { difficulty = "easy" } -max_retries = 4 -headers = ["X-From-Platform: 1"] -taskset = { id = "gsm8k-v1" } -harness = { id = "default" } -group_size = 2 -""" - - -class TestArgvParsing: - def test_only_explicit_flags_are_returned(self): - fields = v0_argv_to_fields( - "reverse-text", - ["--num-examples", "10", "--env-args", '{"difficulty": "hard"}', "-s"], - ) - - assert fields == { - "env_target": "reverse-text", - "num_examples": 10, - "env_args": {"difficulty": "hard"}, - "save_results": True, - } - - def test_unknown_flags_raise_system_exit(self): - with pytest.raises(SystemExit): - v0_argv_to_fields("reverse-text", ["--num-exmaples", "5"]) - - -class TestEvalDispatch: - """--save-results and transitional configs run through the conversion, not a v0 module.""" - - @pytest.fixture - def bridge_env(self, monkeypatch): - class DummyConfig: - api_key = "test-api-key" - inference_url = "https://api.pinference.ai/api/v1" - team_id = None - - class DummyPlugin: - eval_module = "verifiers.v1.cli.eval.main" - - def build_module_command(self, module, args): - return [module, *args] - - class DummyInferenceClient: - def __init__(self, timeout=None): - pass - - def retrieve_model(self, model): - return {"id": model} - - def chat_completion(self, payload, stream=False): - return {"id": "cmpl-123", "choices": []} - - commands = [] - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", DummyInferenceClient) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda ref, env_dir_path: ResolvedEnvironment( - original=ref, env_name=ref.split("/")[-1].split("@")[0], install_mode="local" - ), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: commands.append(command), - ) - return commands - - def _converted_config_from(self, command): - assert command[0] == "verifiers.v1.cli.eval.main" - assert command[1] == "@" - return toml.load(command[2]) - - def test_save_results_argv_converts_to_v1_run(self, bridge_env): - run_eval_passthrough( - environment="reverse-text", - passthrough_args=["--num-examples", "5", "--save-results", "--disable-tui"], - skip_upload=True, - env_path=None, - ) - - config = self._converted_config_from(bridge_env[0]) - assert config["taskset"] == {"id": "reverse-text"} - assert config["num_tasks"] == 5 - assert config["rich"] is False - assert "save_results" not in config - - def test_transitional_config_without_save_results_converts(self, bridge_env, tmp_path): - config_path = tmp_path / "hosted-eval-config.toml" - config_path.write_text(PLATFORM_TRANSITIONAL_TOML) - - # the platform's raw v1 invocation: config path + --skip-upload + TUI flag - run_eval_passthrough( - environment=str(config_path), - passthrough_args=["--disable-tui"], - skip_upload=True, - env_path=None, - ) - - config = self._converted_config_from(bridge_env[0]) - assert config["taskset"] == {"id": "gsm8k-v1", "difficulty": "easy"} - assert config["num_rollouts"] == 2 - assert config["rich"] is False - # prime's run plumbing still applies to the converted config - command = bridge_env[0] - assert "--client.headers" in command - headers = json.loads(command[command.index("--client.headers") + 1]) - assert headers["X-From-Platform"] == "1" - assert "X-PI-Job-Id" in headers - - def test_debug_flag_is_accepted_as_tui_disable(self, bridge_env): - run_eval_passthrough( - environment="reverse-text", - passthrough_args=["--save-results", "--debug"], - skip_upload=True, - env_path=None, - ) - - config = self._converted_config_from(bridge_env[0]) - assert config["rich"] is False - - def test_hub_slug_taskset_is_pinned_to_installed_name(self, bridge_env, tmp_path): - config_path = tmp_path / "hosted-eval-config.toml" - config_path.write_text( - 'model = "m"\n\n[[eval]]\ntaskset = { id = "prime/some-env@0.1.2" }\n' - ) - - run_eval_passthrough( - environment=str(config_path), - passthrough_args=[], - skip_upload=True, - env_path=None, - ) - - config = self._converted_config_from(bridge_env[0]) - assert config["taskset"] == {"id": "some-env"} - - def test_typo_flags_exit_with_usage_error(self, bridge_env): - with pytest.raises(typer.Exit) as exc_info: - run_eval_passthrough( - environment="reverse-text", - passthrough_args=["--save-results", "--num-exmaples", "5"], - skip_upload=True, - env_path=None, - ) - assert exc_info.value.exit_code == 2 - - -def test_prime_eval_default_routing_forms(monkeypatch): - """`prime eval ` / `@ config` / `@config` route to the eval run (no `run` token).""" - from prime_cli.main import app - from typer.testing import CliRunner - - calls = [] - monkeypatch.setattr( - "prime_cli.commands.evals.run_eval_passthrough", - lambda **kwargs: calls.append(kwargs), - ) - - for argv, expected_environment, expected_args in [ - (["eval", "my-env", "-n", "5"], "my-env", ["-n", "5"]), - (["eval", "@", "cfg.toml"], "cfg.toml", []), - (["eval", "@cfg.toml"], "@cfg.toml", []), # the bridge strips the @ prefix - (["eval", "run", "my-env"], "my-env", []), # hidden hosted-sandbox alias - ]: - result = CliRunner().invoke(app, argv, env={"PRIME_DISABLE_VERSION_CHECK": "1"}) - assert result.exit_code == 0, result.output - call = calls.pop() - assert call["environment"] == expected_environment - assert call["passthrough_args"] == expected_args From 7a812a7c3d2133df862ca0b2683b8e3d80fdad2e Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:33:26 +0200 Subject: [PATCH 13/19] fix: address review feedback on resume parsing and validate config prep - a flag-like --resume "value" falls through to the normal invocation so verifiers reports the missing directory instead of prime treating the flag as an output dir - config-driven validate pins hub env refs into a local config copy via _pin_config_env, matching the eval path --- packages/prime/src/prime_cli/verifiers_bridge.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 54977f347..cccd55949 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -941,7 +941,8 @@ def run_eval_passthrough( raise typer.Exit(1) resume_dir = _parse_value_option(passthrough_args, "--resume", None) - if resume_dir is not None: + # a flag-like "value" means --resume had no directory; let verifiers report it + if resume_dir is not None and not resume_dir.startswith("-"): run = _resume_v1_eval(resume_dir, passthrough_args, config) else: run = _run_v1_eval(environment, passthrough_args, config) @@ -972,6 +973,8 @@ def run_validate_passthrough(environment: str, passthrough_args: list[str]) -> N env_dir_path = _pop_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH if is_config: + # install hub refs and pin the local name into a config copy before verifiers parses + target, _ = _pin_config_env(toml.load(target), target, env_dir_path) # pydantic-config reads a root config file as two tokens: `@ path` run_args = ["@", target] else: From b322c9448d946769abc0e5b424ecedf754637adf Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:31:09 +0200 Subject: [PATCH 14/19] refactor: materialize PRIME_* runtime env, rework hosted header overrides - _prime_runtime_env injects PRIME_API_KEY / PRIME_INFERENCE_URL / PRIME_TEAM_ID into every verifiers subprocess now that verifiers reads env vars only; an explicit --api-key-var removes the injected key - hosted override parsing accepts legacy --header pairs alongside v1 --client.headers and folds both into the submission payload - import build_extra_headers from its v1 home (verifiers.v1.cli.eval.compat) --- .../prime/src/prime_cli/commands/evals.py | 81 +++++++++++++------ .../prime/src/prime_cli/verifiers_bridge.py | 32 ++++---- packages/prime/tests/test_eval_billing.py | 3 + packages/prime/tests/test_hosted_eval.py | 6 ++ packages/prime/tests/test_validate.py | 1 + 5 files changed, 85 insertions(+), 38 deletions(-) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 32edaae5b..79b5cf273 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -268,34 +268,69 @@ def _hosted_overrides_from_flags(passthrough_args: list[str]) -> dict[str, Any]: caller explicitly set become overrides.""" if not passthrough_args: return {} + legacy_header_values: list[str] = [] + parsed_args: list[str] = [] + idx = 0 + while idx < len(passthrough_args): + arg = passthrough_args[idx] + if arg == "--header": + if idx + 1 >= len(passthrough_args): + console.print("[red]Error:[/red] --header must be followed by 'Name: Value'") + raise typer.Exit(2) + legacy_header_values.append(passthrough_args[idx + 1]) + idx += 2 + continue + if arg.startswith("--header="): + legacy_header_values.append(arg.split("=", 1)[1]) + idx += 1 + continue + parsed_args.append(arg) + idx += 1 + from pydantic_config import ConfigFileError from pydantic_config import cli as pydantic_cli from verifiers.v1.configs.eval import EvalConfig - try: - parsed = pydantic_cli(EvalConfig, args=list(passthrough_args), prog="prime eval --hosted") - except SystemExit as exc: - raise typer.Exit(exc.code if isinstance(exc.code, int) else 2) from exc - except ConfigFileError as exc: - console.print(f"[red]Error:[/red] {exc}") - raise typer.Exit(2) from exc - overrides: dict[str, Any] = {} - provided = parsed.model_fields_set - if "num_tasks" in provided: - # v1's unset num_tasks means "all"; the platform spells that -1 - overrides["num_examples"] = -1 if parsed.num_tasks is None else parsed.num_tasks - if "num_rollouts" in provided: - overrides["rollouts_per_example"] = parsed.num_rollouts - if "model" in provided: - overrides["model"] = parsed.model - if "max_concurrent" in provided: - overrides["max_concurrent"] = parsed.max_concurrent - if "verbose" in provided: - overrides["verbose"] = parsed.verbose - sampling = parsed.sampling.model_dump(exclude_none=True) - if sampling: - overrides["sampling_args"] = sampling + client_headers: dict[str, str] = {} + if parsed_args: + try: + parsed = pydantic_cli(EvalConfig, args=parsed_args, prog="prime eval --hosted") + except SystemExit as exc: + raise typer.Exit(exc.code if isinstance(exc.code, int) else 2) from exc + except ConfigFileError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + + provided = parsed.model_fields_set + if "num_tasks" in provided: + # v1's unset num_tasks means "all"; the platform spells that -1 + overrides["num_examples"] = -1 if parsed.num_tasks is None else parsed.num_tasks + if "num_rollouts" in provided: + overrides["rollouts_per_example"] = parsed.num_rollouts + if "model" in provided: + overrides["model"] = parsed.model + if "max_concurrent" in provided: + overrides["max_concurrent"] = parsed.max_concurrent + if "verbose" in provided: + overrides["verbose"] = parsed.verbose + sampling = parsed.sampling.model_dump(exclude_none=True) + if sampling: + overrides["sampling_args"] = sampling + if "headers" in parsed.client.model_fields_set: + default_headers = type(parsed.client)().headers + client_headers = { + key: value + for key, value in parsed.client.headers.items() + if key not in default_headers or default_headers[key] != value + } + + if client_headers or legacy_header_values: + headers = _coerce_hosted_headers( + {"headers": client_headers, "header": legacy_header_values} + ) + if headers is not None: + overrides["headers"] = headers return overrides diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index cccd55949..88534ec14 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -300,6 +300,17 @@ def _provider_base_url(provider: Optional[str]) -> Optional[str]: return url.rstrip("/") +def _prime_runtime_env(config: Config) -> dict[str, str]: + env = os.environ.copy() + env["PRIME_API_KEY"] = config.api_key + env["PRIME_INFERENCE_URL"] = config.inference_url + if config.team_id: + env["PRIME_TEAM_ID"] = config.team_id + else: + env.pop("PRIME_TEAM_ID", None) + return env + + def _env_dir_path_arg(args: list[str]) -> str: return _parse_value_option(args, "--env-dir-path", None) or DEFAULT_ENV_DIR_PATH @@ -796,15 +807,15 @@ def _add_default_inference_and_key_args( passthrough_args: list[str], config: Config ) -> tuple[list[str], dict[str, str], str, str]: args = list(passthrough_args) - env = os.environ.copy() + env = _prime_runtime_env(config) model = _parse_value_option(args, "--model", "-m") or DEFAULT_MODEL configured_base = (config.inference_url or "").strip().rstrip("/") base = _parse_value_option(args, "--api-base-url", "-b") provider = _parse_value_option(args, "--provider", "-p") api_key_var = _parse_value_option(args, "--api-key-var", "-k") - if api_key_var is None: - env["PRIME_API_KEY"] = config.api_key + if api_key_var is not None and api_key_var != "PRIME_API_KEY": + env.pop("PRIME_API_KEY", None) if base: base = base.rstrip("/") @@ -964,10 +975,7 @@ def run_validate_passthrough(environment: str, passthrough_args: list[str]) -> N target = environment.removeprefix("@") is_config = _is_config_target(target) args = list(passthrough_args) - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id + env = _prime_runtime_env(config) # prime-only option: verifiers must not see it env_dir_path = _pop_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH @@ -1020,10 +1028,7 @@ def _pin_config_env( def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config) -> V1EvalRun: """Re-run `--resume ` and recover the upload identity from the run's config.toml.""" - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id + env = _prime_runtime_env(config) plugin = load_verifiers_prime_plugin() _run_command(plugin.build_module_command(plugin.eval_module, passthrough_args), env=env) @@ -1056,10 +1061,7 @@ def _run_v1_eval( target = environment.removeprefix("@") is_config = _is_config_target(target) args = list(passthrough_args) - env = os.environ.copy() - env["PRIME_API_KEY"] = config.api_key - if config.team_id: - env["PRIME_TEAM_ID"] = config.team_id + env = _prime_runtime_env(config) config_data: dict = toml.load(target) if is_config else {} config_model = config_data.get("model") diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 94f62a333..eeef70d4e 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -210,6 +210,8 @@ def __init__(self, timeout=None): assert headers["X-PI-Job-Id"].startswith("goblin_questions_gpt_4.1_mini_") assert captured["prepared"] == ("goblin-questions", str(tmp_path / "custom-envs")) assert captured["env"]["PRIME_API_KEY"] == "test-api-key" + assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url + assert "PRIME_TEAM_ID" not in captured["env"] def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): @@ -266,6 +268,7 @@ def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): str(output_dir), ] assert captured["env"]["PRIME_API_KEY"] == "test-api-key" + assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url upload_kwargs = captured["upload"] assert upload_kwargs["env_name"] == "wiki-search" assert upload_kwargs["job_id"] == "existing-job-id" diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index 09a8d9853..32a89895e 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -162,6 +162,7 @@ def fake_run_hosted_evaluation(config, environment_ids=None): captured["max_concurrent"] = config.max_concurrent captured["verbose"] = config.verbose captured["sampling_args"] = config.sampling_args + captured["headers"] = config.headers return {"evaluation_id": "eval-123"} monkeypatch.setattr( @@ -183,6 +184,10 @@ def fake_run_hosted_evaluation(config, environment_ids=None): "4096", "--sampling.temperature", "0.2", + "--client.headers", + '{"X-Test": "yes"}', + "--header", + "X-Legacy: one", ], env={"PRIME_DISABLE_VERSION_CHECK": "1"}, ) @@ -192,6 +197,7 @@ def fake_run_hosted_evaluation(config, environment_ids=None): "max_concurrent": 100, "verbose": True, "sampling_args": {"max_tokens": 4096, "temperature": 0.2}, + "headers": ["X-Test: yes", "X-Legacy: one"], } diff --git a/packages/prime/tests/test_validate.py b/packages/prime/tests/test_validate.py index a5786ef7b..2b13b5415 100644 --- a/packages/prime/tests/test_validate.py +++ b/packages/prime/tests/test_validate.py @@ -112,6 +112,7 @@ def test_validate_environment_id_resolves_and_passes_bare_name(monkeypatch, tmp_ assert "--env-dir-path" not in command # stripped (prime-only) assert prepared == {"env": "gsm8k-v1", "env_dir": str(tmp_path / "envs")} assert captured["env"]["PRIME_API_KEY"] == "test-api-key" + assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url assert captured["env"]["PRIME_TEAM_ID"] == "team-abc" From 613a9e0cf48d37de2c3f72119cf6ac0652deb5fa Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:52:30 +0200 Subject: [PATCH 15/19] refactor: track verifiers' slimmed compat helpers build_extra_headers now takes (headers, header) directly, merge_sampling_args dropped its prefer_existing_keys knob, and PROVIDER_CONFIGS moved from the deleted verifiers.scripts.eval to verifiers.v1.cli.eval.compat (the guarded provider-URL fallback had been silently dead since that module was removed). --- packages/prime/src/prime_cli/commands/evals.py | 3 +-- packages/prime/src/prime_cli/verifiers_bridge.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 79b5cf273..a69d278e0 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -250,7 +250,7 @@ def _coerce_hosted_headers(raw: dict[str, Any]) -> list[str] | None: from verifiers.v1.cli.eval.compat import build_extra_headers try: - normalized = build_extra_headers(raw) + normalized = build_extra_headers(raw.get("headers"), raw.get("header")) except ValueError as exc: console.print(f"[red]Error:[/red] {exc}") raise typer.Exit(1) from exc @@ -475,7 +475,6 @@ def _validate_single_hosted_eval_config( merged.get("sampling_args"), max_tokens=merged.pop("max_tokens", None), temperature=merged.pop("temperature", None), - prefer_existing_keys=True, ) or None ) diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 88534ec14..64520d819 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -287,7 +287,7 @@ def _provider_base_url(provider: Optional[str]) -> Optional[str]: if not provider: return None try: - from verifiers.scripts.eval import PROVIDER_CONFIGS + from verifiers.v1.cli.eval.compat import PROVIDER_CONFIGS except ImportError: return None From 52460ff9c241dff72865cf4e8d0b67351126f459 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:59:37 +0200 Subject: [PATCH 16/19] Convert the platform's v0 eval argv and back-translate native runs in eval view - verifiers_bridge: pop the frozen v0 eval flags out of argv and convert them into a written v1 config (build_v1_eval_config), so the platform sandbox's legacy command line keeps working; --debug/--disable-tui map to --no-rich - module map realigned to what verifiers ships (gepa -> verifiers.scripts.gepa; install/build/setup/tui dropped, prime env build removed) - eval view: back-translate native v1 trace rows to the legacy sample shape at read time (legacy_row) and discover native outputs// run dirs; env/model come from metadata.json instead of dir-name parsing - metadata.json env falls back to the config's env for resume runs - cleanup: merged help loader, shared _require_api_key, dead lab-app helpers, single-use wrappers, stale removed-era comments --- packages/prime/src/prime_cli/commands/env.py | 51 +-- .../prime/src/prime_cli/commands/evals.py | 145 +++--- packages/prime/src/prime_cli/commands/gepa.py | 4 +- .../prime/src/prime_cli/utils/eval_push.py | 18 - .../prime/src/prime_cli/verifiers_bridge.py | 418 +++++++++--------- .../prime/src/prime_cli/verifiers_plugin.py | 7 +- packages/prime/src/prime_lab_app/data.py | 58 +-- .../prime/src/prime_lab_app/eval_records.py | 13 +- .../prime/src/prime_lab_app/eval_render.py | 13 +- packages/prime/tests/test_eval_billing.py | 7 +- packages/prime/tests/test_eval_v0_args.py | 70 +++ packages/prime/tests/test_validate.py | 2 +- .../tests/test_verifiers_plugin_modules.py | 24 + 13 files changed, 424 insertions(+), 406 deletions(-) create mode 100644 packages/prime/tests/test_eval_v0_args.py create mode 100644 packages/prime/tests/test_verifiers_plugin_modules.py diff --git a/packages/prime/src/prime_cli/commands/env.py b/packages/prime/src/prime_cli/commands/env.py index 2fd883872..1ae6e56cb 100644 --- a/packages/prime/src/prime_cli/commands/env.py +++ b/packages/prime/src/prime_cli/commands/env.py @@ -43,7 +43,7 @@ validate_env_var_name, ) from ..utils.time_utils import format_time_ago, iso_timestamp -from ..verifiers_bridge import is_help_request, print_env_build_help, print_env_init_help +from ..verifiers_bridge import is_help_request, print_env_init_help from ..verifiers_plugin import load_verifiers_prime_plugin, resolve_workspace_python from .config import TEAM_ID_PATTERN @@ -1697,7 +1697,7 @@ def init( @app.command( - no_args_is_help=True, + hidden=True, rich_help_panel="Manage", context_settings={ "allow_extra_args": True, @@ -1705,34 +1705,14 @@ def init( "help_option_names": [], }, ) -def build( - ctx: typer.Context, - env_id: Optional[str] = typer.Argument( - None, help="Environment ID (hyphenated, e.g. openenv-echo)" - ), -) -> None: - """Build an OpenEnv-backed environment image.""" - passthrough_args = list(ctx.args) - - if is_help_request(env_id or "", passthrough_args): - print_env_build_help() - raise typer.Exit(0) - - if env_id is None: - console.print("[red]Error:[/red] Missing argument 'ENV_ID'.") - console.print("[dim]Example: prime env build openenv-echo --path ./environments[/dim]") - raise typer.Exit(2) - - if env_id.startswith("-"): - console.print("[red]Error:[/red] Environment ID must be the first argument.") - console.print("[dim]Example: prime env build openenv-echo --path ./environments[/dim]") - raise typer.Exit(2) - - plugin = load_verifiers_prime_plugin() - command = plugin.build_module_command(plugin.build_module, [env_id, *passthrough_args]) - result = subprocess.run(command) - if result.returncode != 0: - raise typer.Exit(result.returncode) +def build() -> None: + """Removed: OpenEnv images must be prebuilt.""" + console.print( + "[red]prime env build was removed.[/red] The OpenEnv image builder no longer ships " + "with verifiers. Build and push the image yourself, then register it in the " + 'environment\'s .build.json ("image", "port", "start_command", "contract").' + ) + raise typer.Exit(1) @app.command(no_args_is_help=True, rich_help_panel="Manage") @@ -2399,10 +2379,7 @@ def execute_install_command(cmd: List[str], env_id: str, version: str, tool: str """ console.print(f"\n[cyan]Installing {env_id}@{version} with {tool}...[/cyan]") - display_command = " ".join(cmd) - if len(cmd) >= 3 and cmd[1] == "-m" and cmd[2].startswith("verifiers.cli.commands."): - display_command = f"prime env install {env_id}" - console.print(f"[dim]Command: {display_command}[/dim]") + console.print(f"[dim]Command: {' '.join(cmd)}[/dim]") process = subprocess.Popen( cmd, @@ -2467,7 +2444,6 @@ def install( """ try: client = APIClient(require_auth=False) - plugin = load_verifiers_prime_plugin() # Validate package manager if with_tool not in ["uv", "pip"]: @@ -2505,10 +2481,7 @@ def install( env_path = Path(path) / env_folder if env_path.exists(): if with_tool == "uv": - cmd_parts = plugin.build_module_command( - plugin.install_module, - [local_name, "--path", path], - ) + cmd_parts = _uv_pip_command("install", "-e", str(env_path)) else: cmd_parts = ["pip", "install", "-e", str(env_path)] installable_envs.append((cmd_parts, local_name, "local", local_name)) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index a69d278e0..35e200da9 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -40,7 +40,6 @@ print_eval_run_help, print_validate_help, run_eval_passthrough, - run_eval_view, run_validate_passthrough, ) @@ -85,8 +84,6 @@ HOSTED_LOGS_STATUS_UPDATE_EVERY_POLLS = 6 EVAL_TABLE_MAX_TEXT_WIDTH = 30 EVAL_RUN_EXAMPLE_COMMAND = "prime eval harbor_v1 -n 1" -EVAL_HOSTED_LABEL = "HOSTED" -EVAL_LOCAL_LABEL = "LOCAL" # Legacy verifiers config fields/flags are accepted through the parser only so # Prime can reject them with the hosted-specific unsupported-option message. HOSTED_EVAL_CONFIG_EXTRA_FIELDS = { @@ -197,7 +194,7 @@ def format_output(data: dict, output: str) -> None: console.print(syntax) -def _parse_json_object_option(raw: Optional[str], option_name: str) -> Optional[dict[str, Any]]: +def _parse_string_map_option(raw: Optional[str], option_name: str) -> Optional[dict[str, str]]: if raw is None: return None try: @@ -210,14 +207,6 @@ def _parse_json_object_option(raw: Optional[str], option_name: str) -> Optional[ console.print(f"[red]Error:[/red] {option_name} must be a JSON object") raise typer.Exit(1) - return parsed - - -def _parse_string_map_option(raw: Optional[str], option_name: str) -> Optional[dict[str, str]]: - parsed = _parse_json_object_option(raw, option_name) - if parsed is None: - return None - for key, value in parsed.items(): if type(key) is not str or type(value) is not str: console.print( @@ -387,14 +376,7 @@ def _resolve_hosted_config_model(raw_config: dict[str, Any], config_path: Path) if "endpoints_path" in raw_config and not endpoints_path_obj.is_absolute(): endpoints_path = str((config_path.parent / endpoints_path_obj).resolve()) - try: - from verifiers.utils.eval_utils import load_endpoints, resolve_endpoints_file - except ImportError as exc: - console.print( - "[red]Error:[/red] verifiers is required to resolve `endpoint_id`. " - "Install the `verifiers` package or use `model` instead." - ) - raise typer.Exit(1) from exc + from verifiers.utils.eval_utils import load_endpoints, resolve_endpoints_file resolved_endpoints_file = resolve_endpoints_file(endpoints_path) if resolved_endpoints_file is None or resolved_endpoints_file.suffix != ".toml": @@ -565,10 +547,12 @@ def _load_v1_hosted_target(config_path: Path) -> Optional[dict[str, Any]]: headers = [f"{key}: {value}" for key, value in headers_map.items()] or None environment = {key: raw[key] for key in _V1_HOSTED_ENV_KEYS if raw.get(key) is not None} + # alias order mirrors EvalConfig's AliasChoices so hosted and local runs + # resolve duplicate count spellings identically optional = { - "num_examples": _first_config_value(raw, "num_tasks", "num_examples"), + "num_examples": _first_config_value(raw, "num_examples", "num_tasks"), "rollouts_per_example": _first_config_value( - raw, "num_rollouts", "rollouts_per_example", "group_size" + raw, "group_size", "rollouts_per_example", "num_rollouts" ), "timeout_minutes": raw.get("timeout_minutes"), "allow_sandbox_access": raw.get("allow_sandbox_access"), @@ -951,16 +935,13 @@ def list_evals( num_examples = metadata.get("num_examples", "-") rollouts_per_example = metadata.get("rollouts_per_example", "-") - env_name = "-" environment_names = e.get("environment_names", []) - if environment_names and len(environment_names) > 0: - env_name = environment_names[0] + env_name = environment_names[0] if environment_names else "-" - is_hosted = bool(e.get("is_hosted")) - execution_mode = EVAL_HOSTED_LABEL if is_hosted else EVAL_LOCAL_LABEL + execution_mode = "HOSTED" if e.get("is_hosted") else "LOCAL" table.add_row( - eval_id if eval_id else "", + eval_id, str(env_name)[:EVAL_TABLE_MAX_TEXT_WIDTH], str(e.get("model_name", ""))[:EVAL_TABLE_MAX_TEXT_WIDTH], str(e.get("status", "")), @@ -1021,13 +1002,6 @@ def get_samples( format_output(data, output) -def _resolve_eval_viewer_url(evaluation_id: str, response: Optional[dict[str, Any]] = None) -> str: - viewer_url = response.get("viewer_url") if response else None - if viewer_url: - return str(viewer_url) - return get_eval_viewer_url(evaluation_id) - - def _push_samples_with_progress( client: EvalsClient, evaluation_id: str, samples: list[dict[str, Any]] ) -> None: @@ -1156,7 +1130,7 @@ def _push_single_eval( console.print("[blue]Finalizing evaluation...[/blue]") finalize_response = client.finalize_evaluation(eval_id, metrics=eval_data.get("metrics")) - viewer_url = _resolve_eval_viewer_url(eval_id, finalize_response) + viewer_url = (finalize_response or {}).get("viewer_url") or get_eval_viewer_url(eval_id) console.print("[green]✓ Evaluation finalized[/green]") console.print() @@ -1185,7 +1159,15 @@ def view_cmd( if limit < 1: console.print("[red]Error:[/red] --limit must be at least 1") raise typer.Exit(1) - run_eval_view(env_dir=env_dir, outputs_dir=outputs_dir, limit=limit) + + from prime_lab_app import run_eval_view + + run_eval_view( + limit=limit, + env_dir=env_dir or DEFAULT_ENV_DIR_PATH, + outputs_dir=outputs_dir or "./outputs", + workspace=Path.cwd(), + ) @subcommands_app.command("tui") @@ -1571,11 +1553,9 @@ def run_eval_cmd( console.print(f"[dim]Example: {EVAL_RUN_EXAMPLE_COMMAND}[/dim]") raise typer.Exit(2) - env_dir_path: Optional[str] = None poll_interval_was_provided = ( ctx.get_parameter_source("poll_interval") == ParameterSource.COMMANDLINE ) - local_passthrough_args = list(passthrough_args) if not hosted: hosted_only_args = { @@ -1601,16 +1581,14 @@ def run_eval_cmd( # everything endpoint/env-specific belongs in the config file overrides = _hosted_overrides_from_flags(passthrough_args) - hosted_target_configs: list[dict[str, Any]] = [] if _is_config_target(environment): v1_target = _load_v1_hosted_target(Path(environment)) - if v1_target is not None: - hosted_target_configs = [v1_target] - else: - hosted_target_configs = _load_hosted_eval_configs(environment) + hosted_target_configs = ( + [v1_target] if v1_target is not None else _load_hosted_eval_configs(environment) + ) else: hosted_target_configs = [ - {"env_id": environment, "env_dir_path": env_dir_path, "model": DEFAULT_MODEL} + {"env_id": environment, "env_dir_path": None, "model": DEFAULT_MODEL} ] parsed_custom_secrets = _parse_string_map_option(custom_secrets, "--custom-secrets") @@ -1644,7 +1622,7 @@ def run_eval_cmd( { "env_id": target_config["env_id"], "environment": target_config.get("environment"), - "env_dir_path": target_config.get("env_dir_path") or env_dir_path, + "env_dir_path": target_config.get("env_dir_path"), "model": merged["model"], "num_examples": num_examples, "rollouts_per_example": rollouts_per_example, @@ -1685,31 +1663,16 @@ def run_eval_cmd( ) raise typer.Exit(1) - grouped_targets: dict[tuple[Any, ...], dict[str, Any]] = {} - target_order: list[tuple[Any, ...]] = [] + grouped_targets: dict[Any, dict[str, Any]] = {} + target_order: list[Any] = [] for target in effective_targets: - group_key = ( - target["model"], - _freeze_json_value(target.get("environment")), - target["num_examples"], - target["rollouts_per_example"], - _freeze_json_value(target.get("env_args")), - target.get("timeout_minutes"), - target.get("allow_sandbox_access", True), - target.get("allow_instances_access", False), - target.get("allow_tunnel_access", True), - _freeze_json_value(target.get("sampling_args")), - target.get("max_concurrent"), - target.get("max_retries"), - _freeze_json_value(target.get("state_columns")), - target.get("independent_scoring", False), - target.get("verbose", False), - _freeze_json_value(target.get("headers")), - _freeze_json_value(target.get("extra_env_kwargs")), - target.get("api_client_type"), - target.get("api_base_url"), - target.get("api_key_var"), - target.get("eval_name"), + # targets that differ only by environment identity share one submission + group_key = _freeze_json_value( + { + key: value + for key, value in target.items() + if key not in ("env_id", "env_dir_path") + } ) if group_key not in grouped_targets: grouped_targets[group_key] = { @@ -1725,7 +1688,7 @@ def run_eval_cmd( for group_key in target_order: group = grouped_targets[group_key] for grouped_target in group["targets"]: - raw_environment = grouped_target.get("environment") + raw_environment = grouped_target["environment"] if raw_environment is not None: # raw v1 configs need no published environment on the platform group["platform_slugs"].append(raw_environment["taskset"]["id"]) @@ -1748,31 +1711,31 @@ def run_eval_cmd( for group_key in target_order: group = grouped_targets[group_key] target = group["target"] - raw_environment = target.get("environment") + raw_environment = target["environment"] hosted_config = HostedEvalConfig( environment_id=group["environment_ids"][0], environment=raw_environment, inference_model=target["model"], num_examples=target["num_examples"], rollouts_per_example=target["rollouts_per_example"], - env_args=target.get("env_args"), - name=target.get("eval_name"), - timeout_minutes=target.get("timeout_minutes"), - allow_sandbox_access=target.get("allow_sandbox_access", True), - allow_instances_access=target.get("allow_instances_access", False), - allow_tunnel_access=target.get("allow_tunnel_access", True), - custom_secrets=target.get("custom_secrets"), - sampling_args=target.get("sampling_args"), - max_concurrent=target.get("max_concurrent"), - max_retries=target.get("max_retries"), - state_columns=target.get("state_columns"), - independent_scoring=target.get("independent_scoring", False), - verbose=target.get("verbose", False), - headers=target.get("headers"), - extra_env_kwargs=target.get("extra_env_kwargs"), - api_client_type=target.get("api_client_type"), - api_base_url=target.get("api_base_url"), - api_key_var=target.get("api_key_var"), + env_args=target["env_args"], + name=target["eval_name"], + timeout_minutes=target["timeout_minutes"], + allow_sandbox_access=target["allow_sandbox_access"], + allow_instances_access=target["allow_instances_access"], + allow_tunnel_access=target["allow_tunnel_access"], + custom_secrets=target["custom_secrets"], + sampling_args=target["sampling_args"], + max_concurrent=target["max_concurrent"], + max_retries=target["max_retries"], + state_columns=target["state_columns"], + independent_scoring=target["independent_scoring"], + verbose=target["verbose"], + headers=target["headers"], + extra_env_kwargs=target["extra_env_kwargs"], + api_client_type=target["api_client_type"], + api_base_url=target["api_base_url"], + api_key_var=target["api_key_var"], ) result = _create_hosted_evaluations( hosted_config, @@ -1814,7 +1777,7 @@ def run_eval_cmd( run_eval_passthrough( environment=environment, - passthrough_args=local_passthrough_args, + passthrough_args=passthrough_args, skip_upload=skip_upload, env_path=env_path, ) diff --git a/packages/prime/src/prime_cli/commands/gepa.py b/packages/prime/src/prime_cli/commands/gepa.py index b1aa75bbb..47409ec69 100644 --- a/packages/prime/src/prime_cli/commands/gepa.py +++ b/packages/prime/src/prime_cli/commands/gepa.py @@ -48,12 +48,12 @@ def run_gepa_cmd( if environment_or_config is None: console.print("[red]Error:[/red] Missing argument 'ENV_OR_CONFIG'.") - console.print("[dim]Example: prime gepa run wordle --max-calls 100[/dim]") + console.print("[dim]Example: prime gepa run wordle --gepa.max-calls 100[/dim]") raise typer.Exit(2) if environment_or_config.startswith("-"): console.print("[red]Error:[/red] Environment/config must be the first argument.") - console.print("[dim]Example: prime gepa run wordle --max-calls 100[/dim]") + console.print("[dim]Example: prime gepa run wordle --gepa.max-calls 100[/dim]") raise typer.Exit(2) run_gepa_passthrough(environment_or_config, passthrough_args) diff --git a/packages/prime/src/prime_cli/utils/eval_push.py b/packages/prime/src/prime_cli/utils/eval_push.py index 54153b756..31916c0ea 100644 --- a/packages/prime/src/prime_cli/utils/eval_push.py +++ b/packages/prime/src/prime_cli/utils/eval_push.py @@ -23,24 +23,6 @@ console = get_console() -def find_latest_eval_output_dir(env_name: str, model: str) -> Path: - """The newest run directory in the legacy (v0) eval output layout.""" - module_name = env_name.replace("-", "_") - env_model_str = f"{env_name}--{model.replace('/', '--')}" - local_env_dir = Path("./environments") / module_name - base_evals_dir = ( - local_env_dir / "outputs" / "evals" / env_model_str - if local_env_dir.exists() - else Path("./outputs") / "evals" / env_model_str - ) - if not base_evals_dir.exists(): - raise FileNotFoundError(f"Evaluation output directory not found: {base_evals_dir}") - subdirs = [d for d in base_evals_dir.iterdir() if d.is_dir()] - if not subdirs: - raise FileNotFoundError(f"No evaluation results found in {base_evals_dir}") - return max(subdirs, key=lambda d: d.stat().st_mtime) - - def push_eval_results_to_hub( env_name: str, job_id: str, diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 64520d819..18a6cd667 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -37,19 +37,15 @@ MODULE_TO_PRIME_COMMAND = { "verifiers.v1.cli.eval.main": "prime eval", "verifiers.v1.cli.validate": "prime eval validate", - "verifiers.cli.commands.gepa": "prime gepa run", - "verifiers.cli.commands.init": "prime env init", "verifiers.v1.cli.init": "prime env init", - "verifiers.cli.commands.install": "prime env install", - "verifiers.cli.commands.build": "prime env build", - "verifiers.cli.commands.setup": "prime lab setup", - "verifiers.cli.tui": "prime eval view", + "verifiers.scripts.gepa": "prime gepa run", } MODULE_TO_CONSOLE_SCRIPT = { "verifiers.v1.cli.eval.main": "eval", "verifiers.v1.cli.init": "init", "verifiers.v1.cli.validate": "validate", + "verifiers.scripts.gepa": "vf-gepa", } @@ -68,16 +64,8 @@ class ResolvedEnvironment: local_env_path: Optional[Path] = None -@dataclass(frozen=True) -class EndpointResolution: - model: str - base_url: str - - def is_help_request(primary_arg: str, passthrough_args: list[str]) -> bool: - if primary_arg in ("-h", "--help"): - return True - return any(arg in ("-h", "--help") for arg in passthrough_args) + return any(arg in ("-h", "--help") for arg in (primary_arg, *passthrough_args)) def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> str: @@ -126,7 +114,7 @@ def _sanitize_help_text(help_text: str, module_name: str, prime_command: str) -> return sanitized.rstrip() + "\n" -def _load_help_text(module_name: str, prime_command: str) -> str: +def _load_module_help(module_name: str, prime_command: str) -> str: plugin = load_verifiers_prime_plugin() command = plugin.build_module_command(module_name, ["--help"]) result = subprocess.run(command, capture_output=True, text=True) @@ -137,19 +125,14 @@ def _load_help_text(module_name: str, prime_command: str) -> str: help_text += result.stderr if not help_text.strip(): - raise RuntimeError(f"Unable to load help text from {module_name}") + console.print( + f"[red]Failed to load help for {prime_command}:[/red] no output from {module_name}" + ) + raise typer.Exit(1) return _sanitize_help_text(help_text, module_name, prime_command) -def _load_module_help(module_name: str, prime_command: str) -> str: - try: - return _load_help_text(module_name, prime_command) - except Exception as exc: - console.print(f"[red]Failed to load help for {prime_command}:[/red] {exc}") - raise typer.Exit(1) from exc - - def _write_help(text: str) -> None: sys.stdout.write(text) sys.stdout.flush() @@ -198,29 +181,13 @@ def print_env_init_help() -> None: _write_help(_load_module_help(plugin.init_module, "prime env init")) -def print_env_build_help() -> None: - plugin = load_verifiers_prime_plugin() - _write_help(_load_module_help(plugin.build_module, "prime env build")) - - def print_validate_help() -> None: plugin = load_verifiers_prime_plugin() _write_help(_load_module_help(plugin.validate_module, "prime eval validate")) -def run_eval_view(env_dir: Optional[str], outputs_dir: Optional[str], limit: int = 50) -> None: - from prime_lab_app import run_eval_view as run_prime_eval_view - - run_prime_eval_view( - limit=limit, - env_dir=env_dir or "./environments", - outputs_dir=outputs_dir or "./outputs", - workspace=Path.cwd(), - ) - - def _parse_value_option( - args: list[str], long_flag: str, short_flag: Optional[str] + args: list[str], long_flag: str, short_flag: Optional[str] = None ) -> Optional[str]: for idx, arg in enumerate(args): if arg == long_flag or arg == short_flag: @@ -234,15 +201,6 @@ def _parse_value_option( return None -def _has_flag(args: list[str], long_flag: str, short_flag: str) -> bool: - for arg in args: - if arg == long_flag or arg == short_flag: - return True - if arg.startswith(f"{long_flag}="): - return True - return False - - def _pop_value_option(args: list[str], long_flag: str) -> Optional[str]: """Return the value of `long_flag` and remove flag + value from `args` in place.""" for idx, arg in enumerate(args): @@ -256,48 +214,29 @@ def _pop_value_option(args: list[str], long_flag: str) -> Optional[str]: return None -def _resolve_endpoint_alias(args: list[str], model: str) -> Optional[EndpointResolution]: +def _is_endpoint_alias(args: list[str], model: str) -> bool: + """Whether `model` names an endpoints.toml alias gepa resolves natively.""" endpoints_path = _parse_value_option(args, "--endpoints-path", "-e") or DEFAULT_ENDPOINTS_PATH - try: - from verifiers.utils.eval_utils import load_endpoints, resolve_endpoints_file - except ImportError: - return None + from verifiers.utils.eval_utils import load_endpoints, resolve_endpoints_file endpoints_file = resolve_endpoints_file(endpoints_path) if endpoints_file is None or not endpoints_file.exists(): - return None - + return False try: - endpoints = load_endpoints(str(endpoints_file)) - except (ImportError, AttributeError, OSError, ValueError): - return None - - endpoint_group = endpoints.get(model) - if not endpoint_group: - return None + return model in load_endpoints(str(endpoints_file)) + except (OSError, ValueError): + return False - endpoint = endpoint_group[0] - return EndpointResolution( - model=str(endpoint.get("model") or model), - base_url=str(endpoint.get("url") or "").rstrip("/"), - ) - -def _provider_base_url(provider: Optional[str]) -> Optional[str]: - if not provider: - return None - try: - from verifiers.v1.cli.eval.compat import PROVIDER_CONFIGS - except ImportError: - return None +def _provider_endpoint(provider: str) -> tuple[str, str]: + """Resolve the v0 --provider shorthand to (base_url, api_key_var).""" + from verifiers.v1.cli.eval.compat import PROVIDER_CONFIGS provider_config = PROVIDER_CONFIGS.get(provider) - if not provider_config: - return None - url = provider_config.get("url") - if not isinstance(url, str) or not url: - return None - return url.rstrip("/") + if provider_config is None or provider_config.get("client_type"): + console.print(f"[red]Error:[/red] unsupported provider '{provider}'.") + raise typer.Exit(1) + return provider_config["url"].rstrip("/"), provider_config["key"] def _prime_runtime_env(config: Config) -> dict[str, str]: @@ -311,10 +250,6 @@ def _prime_runtime_env(config: Config) -> dict[str, str]: return env -def _env_dir_path_arg(args: list[str]) -> str: - return _parse_value_option(args, "--env-dir-path", None) or DEFAULT_ENV_DIR_PATH - - def _is_config_target(raw: str) -> bool: if raw.endswith(".toml"): return True @@ -348,9 +283,7 @@ def _split_owner_and_name(slug: str) -> Optional[tuple[str, str]]: return owner, name -def _environment_url_from_slug(slug: str) -> Optional[str]: - if _split_owner_and_name(slug) is None: - return None +def _environment_url_from_slug(slug: str) -> str: frontend_url = Config().frontend_url.rstrip("/") return f"{frontend_url}/dashboard/environments/{slug}" @@ -432,7 +365,7 @@ def _fetch_user_slug(client: APIClient) -> Optional[str]: except APIError: return None - data = response.get("data") if isinstance(response, dict) else None + data = response.get("data") if not isinstance(data, dict): return None @@ -451,7 +384,7 @@ def _fetch_active_team_slug(client: APIClient, active_team_id: Optional[str]) -> except APIError: return None - teams = response.get("data") if isinstance(response, dict) else None + teams = response.get("data") if not isinstance(teams, list): return None @@ -475,14 +408,11 @@ def _fetch_remote_env_details( response = client.get(f"/environmentshub/{owner_slug}/{env_name}/@{version}") except APIError: return None - details = response.get("data", response) if isinstance(response, dict) else None + details = response.get("data", response) return details if isinstance(details, dict) else {} -def _extract_remote_version_details(details: Optional[dict]) -> tuple[Optional[str], Optional[str]]: - if not isinstance(details, dict): - return None, None - +def _extract_remote_version_details(details: dict) -> tuple[Optional[str], Optional[str]]: version_block = details.get("latest_version") if isinstance(version_block, dict): semantic = version_block.get("semantic_version") @@ -503,9 +433,9 @@ def _resolve_local_env_display( local_dir: Path, client: Optional[APIClient], ) -> tuple[str, Optional[str], Optional[str], bool, Optional[str]]: - metadata = get_environment_metadata(local_dir) - owner = metadata.get("owner") if isinstance(metadata, dict) else None - tracked_name = metadata.get("name") if isinstance(metadata, dict) else None + metadata = get_environment_metadata(local_dir) or {} + owner = metadata.get("owner") + tracked_name = metadata.get("name") tracked_slug: Optional[str] = None if isinstance(owner, str) and isinstance(tracked_name, str) and owner and tracked_name: tracked_slug = f"{owner}/{tracked_name}" @@ -530,11 +460,11 @@ def _resolve_local_env_display( remote_version, remote_hash = _extract_remote_version_details(remote_details) local_hash = _compute_local_content_hash(local_dir) - local_meta_hash = metadata.get("content_hash") if isinstance(metadata, dict) else None + local_meta_hash = metadata.get("content_hash") if local_hash is None and _is_valid_hash(local_meta_hash): local_hash = str(local_meta_hash) - local_version = metadata.get("version") if isinstance(metadata, dict) else None + local_version = metadata.get("version") if not isinstance(local_version, str): local_version = None @@ -586,15 +516,13 @@ def _resolve_environment_reference( base_ref, version = _split_version(env_reference) if _is_slug_reference(base_ref): - parts = base_ref.split("/", 1) - if len(parts) != 2 or not parts[0] or not parts[1]: + parts = _split_owner_and_name(base_ref) + if parts is None: console.print(f"[red]Invalid environment reference: {env_reference}[/red]") raise typer.Exit(1) - owner, env_name = parts - install_slug = f"{owner}/{env_name}" - if version: - install_slug = f"{install_slug}@{version}" - upstream_slug = f"{owner}/{env_name}" + env_name = parts[1] + upstream_slug = base_ref + install_slug = f"{upstream_slug}@{version}" if version else upstream_slug return ResolvedEnvironment( original=env_reference, env_name=env_name, @@ -675,10 +603,8 @@ def _resolve_environment_reference( selected_label, selected_owner = _choose_remote_owner( env_name, [(label, slug) for label, slug, _ in found] ) - install_slug = f"{selected_owner}/{env_name}" - if version: - install_slug = f"{install_slug}@{version}" upstream_slug = f"{selected_owner}/{env_name}" + install_slug = f"{upstream_slug}@{version}" if version else upstream_slug console.print( f"[dim]Using remote environment {selected_owner}/{env_name} ({selected_label})[/dim]" ) @@ -701,28 +627,20 @@ def _run_command(command: list[str], env: Optional[dict[str, str]] = None) -> No def _install_local_environment(env_path: Path) -> None: - """Make a local checkout importable for verifiers (which no longer installs anything).""" + """Make a local checkout importable; verifiers itself never installs environments.""" from .commands.env import _uv_pip_command _run_command(_uv_pip_command("install", "-e", str(env_path))) -def _is_installed(env_name: str, version: Optional[str]) -> bool: - from .commands.env import _is_environment_installed - - return _is_environment_installed(env_name, version) - - def _install_remote_environment(env_slug: str) -> None: - from .commands.env import _install_single_environment + from .commands.env import _install_single_environment, _is_environment_installed + # resolution only hands us owner/name[@version] slugs slug_no_version, version = _split_version(env_slug) - if "/" not in slug_no_version: - console.print(f"[red]Invalid remote environment slug: {env_slug}[/red]") - raise typer.Exit(1) - _, env_name = slug_no_version.split("/", 1) + env_name = slug_no_version.split("/", 1)[1] - if _is_installed(env_name, version): + if _is_environment_installed(env_name, version): return if not _install_single_environment(env_slug): @@ -738,15 +656,14 @@ def _prepare_single_environment(env_reference: str, env_dir_path: str) -> Resolv _install_local_environment(resolved.local_env_path) return resolved if resolved.install_mode == "remote": - if resolved.install_slug is None: - console.print(f"[red]Could not resolve remote slug for {env_reference}[/red]") - raise typer.Exit(1) if resolved.env_display_id: console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") _install_remote_environment(resolved.install_slug) return resolved - if not _is_installed(resolved.env_name, version=None): + from .commands.env import _is_environment_installed + + if not _is_environment_installed(resolved.env_name): console.print( f"[yellow]Warning:[/yellow] No local checkout or matching remote environment found " f"for '{resolved.env_name}'. Continuing with installed package resolution." @@ -767,15 +684,10 @@ def _prepare_v1_environment(env_reference: str, env_dir_path: str) -> ResolvedEn _install_local_environment(resolved.local_env_path) elif resolved.install_mode == "remote": console.print(f"[dim]Resolved source: {resolved.env_display_id}[/dim]") - _install_remote_environment(resolved.install_slug or env_reference) + _install_remote_environment(resolved.install_slug) return resolved -def _env_name_from_reference(env_reference: str) -> str: - base_ref, _version = _split_version(env_reference) - return base_ref.rsplit("/", 1)[-1] - - def _collect_gepa_config_env(config_path: Path, fallback_env_dir: str) -> Optional[tuple[str, str]]: try: raw = toml.load(config_path) @@ -786,14 +698,13 @@ def _collect_gepa_config_env(config_path: Path, fallback_env_dir: str) -> Option ) return None - if not isinstance(raw, dict): - return None - - env_table = raw.get("env") - if not isinstance(env_table, dict): - return None - - env_id = env_table.get("env_id") + # current gepa configs: top-level `id` or an `[[env]]` list; old ones: an `[env]` + # table with `env_id` + env_entries = raw.get("env") + first_env = env_entries[0] if isinstance(env_entries, list) and env_entries else env_entries + env_id = raw.get("id") + if not env_id and isinstance(first_env, dict): + env_id = first_env.get("id") or first_env.get("env_id") if not isinstance(env_id, str) or not env_id: return None @@ -803,39 +714,52 @@ def _collect_gepa_config_env(config_path: Path, fallback_env_dir: str) -> Option return (env_id, env_dir_path) +# v0-era short flags rewritten to the long forms GEPAConfig's typed CLI accepts. +_GEPA_SHORT_FLAGS = { + "-m": "--model", + "-b": "--api-base-url", + "-k": "--api-key-var", + "-p": "--provider", + "-e": "--endpoints-path", +} + + def _add_default_inference_and_key_args( passthrough_args: list[str], config: Config -) -> tuple[list[str], dict[str, str], str, str]: - args = list(passthrough_args) +) -> tuple[list[str], dict[str, str]]: + """Normalize gepa args for verifiers' typed CLI (long flags only, no --provider) and + default the base URL to the configured Prime inference URL. An endpoints.toml alias + given as the model is left alone — gepa resolves it natively.""" + args = [_GEPA_SHORT_FLAGS.get(arg, arg) for arg in passthrough_args] env = _prime_runtime_env(config) - model = _parse_value_option(args, "--model", "-m") or DEFAULT_MODEL - configured_base = (config.inference_url or "").strip().rstrip("/") - base = _parse_value_option(args, "--api-base-url", "-b") - provider = _parse_value_option(args, "--provider", "-p") - api_key_var = _parse_value_option(args, "--api-key-var", "-k") + model = _parse_value_option(args, "--model") or DEFAULT_MODEL + base = _parse_value_option(args, "--api-base-url") + api_key_var = _parse_value_option(args, "--api-key-var") + + # GEPAConfig has no provider field: resolve the shorthand here and strip it. + provider = _pop_value_option(args, "--provider") + if provider is not None: + provider_base, provider_key_var = _provider_endpoint(provider) + if base is None: + base = provider_base + args.extend(["--api-base-url", base]) + if api_key_var is None: + api_key_var = provider_key_var + args.extend(["--api-key-var", api_key_var]) + + if base is None and not _is_endpoint_alias(args, model): + base = (config.inference_url or "").strip().rstrip("/") + if not base: + console.print( + "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." + ) + raise typer.Exit(1) + args.extend(["--api-base-url", base]) + if api_key_var is not None and api_key_var != "PRIME_API_KEY": env.pop("PRIME_API_KEY", None) - - if base: - base = base.rstrip("/") - elif provider is not None: - base = _provider_base_url(provider) or "" - elif endpoint := _resolve_endpoint_alias(args, model): - return args, env, endpoint.model, endpoint.base_url - elif configured_base: - base = configured_base - args.extend(["-b", base]) - else: - console.print( - "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." - ) - raise typer.Exit(1) - - if api_key_var is None and provider is None: - args.extend(["-k", "PRIME_API_KEY"]) - - return args, env, model, base + return args, env def _validate_model(model: str, inference_base_url: str, configured_base_url: str) -> None: @@ -936,6 +860,15 @@ class V1EvalRun: is_config: bool = False +def _require_api_key(config: Config) -> None: + if not config.api_key: + console.print( + "[red]No API key configured.[/red] " + "Run [bold]prime login[/bold] or [bold]prime config set-api-key[/bold]." + ) + raise typer.Exit(1) + + def run_eval_passthrough( environment: str, passthrough_args: list[str], @@ -944,14 +877,9 @@ def run_eval_passthrough( env_path: Optional[str], ) -> None: config = Config() - if not config.api_key: - console.print( - "[red]No API key configured.[/red] " - "Run [bold]prime login[/bold] or [bold]prime config set-api-key[/bold]." - ) - raise typer.Exit(1) + _require_api_key(config) - resume_dir = _parse_value_option(passthrough_args, "--resume", None) + resume_dir = _parse_value_option(passthrough_args, "--resume") # a flag-like "value" means --resume had no directory; let verifiers report it if resume_dir is not None and not resume_dir.startswith("-"): run = _resume_v1_eval(resume_dir, passthrough_args, config) @@ -965,22 +893,16 @@ def run_validate_passthrough(environment: str, passthrough_args: list[str]) -> N environment resolution and auth env vars. Validate is fire-and-forget — nothing is written to disk or uploaded, so there is no model, output-dir, resume, or dry-run path.""" config = Config() - if not config.api_key: - console.print( - "[red]No API key configured.[/red] " - "Run [bold]prime login[/bold] or [bold]prime config set-api-key[/bold]." - ) - raise typer.Exit(1) + _require_api_key(config) target = environment.removeprefix("@") - is_config = _is_config_target(target) args = list(passthrough_args) env = _prime_runtime_env(config) # prime-only option: verifiers must not see it env_dir_path = _pop_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH - if is_config: + if _is_config_target(target): # install hub refs and pin the local name into a config copy before verifiers parses target, _ = _pin_config_env(toml.load(target), target, env_dir_path) # pydantic-config reads a root config file as two tokens: `@ path` @@ -1035,7 +957,8 @@ def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config output_dir = Path(resume_dir) saved_config = toml.load(output_dir / "config.toml") model = saved_config["model"] - env_name = _env_name_from_reference(saved_config["taskset"]["id"]) + taskset_ref, _version = _split_version(saved_config["taskset"]["id"]) + env_name = taskset_ref.rsplit("/", 1)[-1] saved_headers = saved_config.get("client", {}).get("headers", {}) display_id = saved_headers.get(INTERNAL_ENV_DISPLAY_HEADER) # display values like "name (local - ahead of org/name)" carry a "/" but are not slugs @@ -1048,6 +971,87 @@ def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config ) +# The frozen v0 eval argv hosted sandboxes still emit, mapped to the v0 config fields +# verifiers' compat layer converts. Flags the v1 CLI parses natively (--model, --verbose, +# --max-concurrent, --extra-env-kwargs) stay on the command line. +_V0_EVAL_VALUE_FLAGS = { + "--env-args": "env_args", + "--sampling-args": "sampling_args", + "--max-retries": "max_retries", + "--state-columns": "state_columns", + "--api-client-type": "api_client_type", + "--api-base-url": "api_base_url", + "--api-key-var": "api_key_var", + "--num-examples": "num_examples", + "--rollouts-per-example": "rollouts_per_example", +} +_V0_EVAL_TRIGGER_FLAGS = ( + set(_V0_EVAL_VALUE_FLAGS) + | {"--save-results", "--debug", "--disable-tui", "--independent-scoring", "--header"} +) - {"--num-examples", "--rollouts-per-example"} # both are valid v1 aliases + + +def _pop_v0_eval_args(args: list[str]) -> tuple[dict, bool]: + """Pop the v0 eval dialect out of argv; returns (v0 fields, tui disabled). + + Only kicks in when a v0-only flag is present (hosted sandboxes and old scripts); + pure v1 invocations pass through untouched.""" + present = {arg.split("=", 1)[0] for arg in args} + tui_disabled = False + for flag in ("--debug", "--disable-tui"): + while flag in args: + args.remove(flag) + tui_disabled = True + if not present & _V0_EVAL_TRIGGER_FLAGS: + return {}, tui_disabled + + fields: dict = {} + while "--save-results" in args: + args.remove("--save-results") # v1 always saves + while "--independent-scoring" in args: + args.remove("--independent-scoring") + fields["independent_scoring"] = True + for flag, field in _V0_EVAL_VALUE_FLAGS.items(): + while (value := _pop_value_option(args, flag)) is not None: + fields[field] = value + headers = [] + while (value := _pop_value_option(args, "--header")) is not None: + headers.append(value) + if headers: + fields["header"] = headers + + try: + for field in ("env_args", "sampling_args"): + if isinstance(fields.get(field), str): + fields[field] = json.loads(fields[field]) + for field in ("num_examples", "rollouts_per_example"): + if field in fields: + fields[field] = int(fields[field]) + except (json.JSONDecodeError, ValueError) as exc: + console.print(f"[red]Error:[/red] invalid v0 eval flag value: {exc}") + raise typer.Exit(2) from exc + return fields, tui_disabled + + +def _convert_v0_eval_args(target: str, fields: dict) -> str: + """Convert popped v0 flags + the env target into a runnable v1 config file.""" + from verifiers.v1.cli.eval.compat import build_v1_eval_config, write_converted_eval_config + + fields["id"] = target + try: + converted, warnings = build_v1_eval_config(fields) + except ValueError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + for warning in warnings: + console.print(f"[yellow]warning:[/yellow] {warning}") + return str( + write_converted_eval_config( + converted, header_comment=f"converted v0 eval flags by prime ({target})" + ) + ) + + def _run_v1_eval( environment: str, passthrough_args: list[str], @@ -1056,13 +1060,26 @@ def _run_v1_eval( """Prepare and run a fresh v1 eval: fill in prime's model/base-url/output-dir defaults, make the environment importable, and tag the run with a job id header. - Legacy (v0) inputs need no handling here: verifiers auto-detects v0 env ids and - converts transitional configs at its own ingestion boundary.""" + Transitional configs convert at verifiers' own ingestion boundary; the frozen v0 + *argv* dialect (hosted sandboxes) converts here via the same compat layer.""" target = environment.removeprefix("@") is_config = _is_config_target(target) args = list(passthrough_args) env = _prime_runtime_env(config) + v0_fields, tui_disabled = _pop_v0_eval_args(args) + if tui_disabled: + args.append("--no-rich") + if v0_fields: + if is_config: + console.print( + "[red]Error:[/red] v0 eval flags can't be combined with a config file; " + "set them in the config instead." + ) + raise typer.Exit(2) + target = _convert_v0_eval_args(target, v0_fields) + is_config = True + config_data: dict = toml.load(target) if is_config else {} config_model = config_data.get("model") cli_model = _parse_value_option(args, "--model", "-m") @@ -1073,7 +1090,7 @@ def _run_v1_eval( configured_base_url = (config.inference_url or "").strip().rstrip("/") config_client = config_data.get("client") config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None - cli_base_url = _parse_value_option(args, "--client.base-url", None) + cli_base_url = _parse_value_option(args, "--client.base-url") base_url = cli_base_url or config_base_url or configured_base_url if not base_url: console.print( @@ -1164,17 +1181,16 @@ def _upload_v1_results(run: V1EvalRun, *, skip_upload: bool, env_path: Optional[ console.print("[dim]No rollout results produced.[/dim]") return + from collections import Counter + from verifiers.v1.cli.output import read_upload_data upload = read_upload_data(run.output_dir) # `prime eval view` only lists runs that have a metadata.json; keep writing one. - rollout_counts: dict[object, int] = {} - for row in upload.results: - if "example_id" in row: - rollout_counts[row["example_id"]] = rollout_counts.get(row["example_id"], 0) + 1 + rollout_counts = Counter(row["example_id"] for row in upload.results if "example_id" in row) metadata = { - "env": run.env_name, + "env": run.env_name or upload.env, # resume runs carry no env_name "model": upload.model_name, "num_examples": len(rollout_counts), "avg_reward": upload.metrics.get("reward", 0.0), @@ -1226,16 +1242,10 @@ def _upload_v1_results(run: V1EvalRun, *, skip_upload: bool, env_path: Optional[ def run_gepa_passthrough(environment_or_config: str, passthrough_args: list[str]) -> None: plugin = load_verifiers_prime_plugin() config = Config() + _require_api_key(config) - if not config.api_key: - console.print( - "[red]No API key configured.[/red] " - "Run [bold]prime login[/bold] or [bold]prime config set-api-key[/bold]." - ) - raise typer.Exit(1) - - args, env, _model, _base_url = _add_default_inference_and_key_args(passthrough_args, config) - env_dir_path = _env_dir_path_arg(args) + args, env = _add_default_inference_and_key_args(passthrough_args, config) + env_dir_path = _parse_value_option(args, "--env-dir-path") or DEFAULT_ENV_DIR_PATH run_target = environment_or_config if _is_config_target(environment_or_config): diff --git a/packages/prime/src/prime_cli/verifiers_plugin.py b/packages/prime/src/prime_cli/verifiers_plugin.py index b8dc17f78..f56c8f582 100644 --- a/packages/prime/src/prime_cli/verifiers_plugin.py +++ b/packages/prime/src/prime_cli/verifiers_plugin.py @@ -88,9 +88,7 @@ class PrimeVerifiersPlugin: eval_module: str = V1_EVAL_MODULE init_module: str = V1_INIT_MODULE validate_module: str = V1_VALIDATE_MODULE - gepa_module: str = "verifiers.cli.commands.gepa" - install_module: str = "verifiers.cli.commands.install" - build_module: str = "verifiers.cli.commands.build" + gepa_module: str = "verifiers.scripts.gepa" def build_module_command( self, module_name: str, args: Sequence[str] | None = None @@ -104,6 +102,5 @@ def build_module_command( def load_verifiers_prime_plugin() -> PrimeVerifiersPlugin: - """The static verifiers command map. Verifiers no longer exports a plugin module; the - old import handshake always resolved to these values anyway.""" + """The static verifiers command map (verifiers stopped exporting a plugin module).""" return PrimeVerifiersPlugin() diff --git a/packages/prime/src/prime_lab_app/data.py b/packages/prime/src/prime_lab_app/data.py index 2155ea056..4582903db 100644 --- a/packages/prime/src/prime_lab_app/data.py +++ b/packages/prime/src/prime_lab_app/data.py @@ -109,8 +109,8 @@ def load_initial(self, options: LabLoadOptions) -> LabSnapshot: cache_key = _row_cache_key(options, config, team) detail_cache_key = _account_cache_key(config, team) cached_sections = load_cached_lab_sections(cache_key, limit=options.limit) - local_environment_items = tuple( - _workspace_environment_items( + workspace_env_items = tuple( + local_environment_items( options.workspace.resolve(), options.env_dir, options.limit, @@ -126,7 +126,7 @@ def load_initial(self, options: LabLoadOptions) -> LabSnapshot: "Environments", "Local and platform environments.", authenticated=True, - local_items=local_environment_items, + local_items=workspace_env_items, cached_section=cached_sections.get("environments"), ), _cached_or_loading_section( @@ -282,7 +282,7 @@ def _workspace_section( limit=options.limit, ), *_workspace_profile_items(profiles, current_profile), - *_workspace_environment_items( + *local_environment_items( workspace, options.env_dir, options.limit, @@ -713,10 +713,6 @@ def _load_environment_detail(self, item: LabItem) -> LabItem: ) -def load_lab_snapshot(options: LabLoadOptions) -> LabSnapshot: - return LabDataSource().load(options) - - def _row_cache_key(options: LabLoadOptions, config: Config, team: str | None) -> str: return lab_row_cache_key( workspace=options.workspace.resolve(), @@ -1002,17 +998,22 @@ def discover_local_eval_runs( outputs_dir: str = "./outputs", limit: int = 30, ) -> list[dict[str, Any]]: + # Legacy runs live under outputs/evals//; native v1 runs live + # directly under outputs// (the `evals` child has no "--" and is skipped). roots: list[Path] = [] env_root = (workspace / env_dir).resolve() if _safe_is_dir(env_root): for env_path in _safe_sorted_children(env_root): - candidate = env_path / "outputs" / "evals" - if _safe_is_dir(candidate): - roots.append(candidate) + for candidate in (env_path / "outputs" / "evals", env_path / "outputs"): + if _safe_is_dir(candidate): + roots.append(candidate) - global_root = (workspace / outputs_dir / "evals").resolve() - if _safe_is_dir(global_root): - roots.append(global_root) + for candidate in ( + (workspace / outputs_dir / "evals").resolve(), + (workspace / outputs_dir).resolve(), + ): + if _safe_is_dir(candidate): + roots.append(candidate) runs: list[dict[str, Any]] = [] for root in roots: @@ -1033,8 +1034,10 @@ def discover_local_eval_runs( metadata = _read_json_file(metadata_path) runs.append( { - "env_id": env_id, - "model": model, + # the metadata is authoritative; dir-name parsing can't recover + # native names like ---- exactly + "env_id": str(metadata.get("env") or metadata.get("env_id") or env_id), + "model": str(metadata.get("model") or model), "run_id": run_dir.name, "path": str(run_dir), "metadata": metadata, @@ -1607,12 +1610,6 @@ def _workspace_profile_items(profiles: list[str], current_profile: str) -> list[ return items -def _workspace_environment_items( - workspace: Path, env_dir: str, limit: int, *, section: str -) -> list[LabItem]: - return local_environment_items(workspace, env_dir, limit, section=section) - - def _workspace_config_items(workspace: Path, limit: int) -> list[LabItem]: configs_root = workspace / "configs" if not configs_root.is_dir(): @@ -1678,13 +1675,6 @@ def _config_current_profile(config: Config) -> str: return str(getattr(config, "current_environment", None) or "production") -def _workspace_path(workspace: Path, value: str) -> Path: - path = Path(value).expanduser() - if not path.is_absolute(): - path = workspace / path - return path.resolve() - - def _relative_path(path: Path, root: Path) -> str: try: return str(path.resolve().relative_to(root.resolve())) @@ -1692,16 +1682,6 @@ def _relative_path(path: Path, root: Path) -> str: return str(path) -def _interesting_child_files(path: Path) -> list[str]: - names = [] - for child in sorted(path.iterdir()): - if child.name.startswith("."): - continue - if child.is_file() and child.suffix in {".py", ".toml", ".md", ".json"}: - names.append(child.name) - return names[:12] - - def _read_toml_preview(path: Path) -> tuple[dict[str, Any], str]: try: toml_text = path.read_text(encoding="utf-8") diff --git a/packages/prime/src/prime_lab_app/eval_records.py b/packages/prime/src/prime_lab_app/eval_records.py index 4cedc03eb..1badf6d90 100644 --- a/packages/prime/src/prime_lab_app/eval_records.py +++ b/packages/prime/src/prime_lab_app/eval_records.py @@ -10,6 +10,17 @@ from .models import LabItem +def legacy_row(data: dict[str, Any]) -> dict[str, Any]: + """Back-translate a native v1 trace row into the legacy sample shape the viewer + renders (prompt/completion/reward/trajectory); legacy rows pass through.""" + if "nodes" not in data and "rewards" not in data: + return data + from verifiers.v1.cli.output import convert_results_for_upload + + converted = convert_results_for_upload([data]) + return converted[0] if converted else {} + + @dataclass class LocalEvalRun: """A local evaluation run discovered from a verifiers output directory.""" @@ -175,7 +186,7 @@ def get(self, index: int) -> dict[str, Any]: data = {} finally: self._fh.seek(position) - data = data if isinstance(data, dict) else {} + data = legacy_row(data) if isinstance(data, dict) else {} self._cache[index] = data return data diff --git a/packages/prime/src/prime_lab_app/eval_render.py b/packages/prime/src/prime_lab_app/eval_render.py index 952ed6994..f4a592c9f 100644 --- a/packages/prime/src/prime_lab_app/eval_render.py +++ b/packages/prime/src/prime_lab_app/eval_render.py @@ -12,7 +12,13 @@ from rich.table import Table from rich.text import Text -from .eval_records import LocalEvalRun, MetricSummary, RunOverviewStats, parse_log_header +from .eval_records import ( + LocalEvalRun, + MetricSummary, + RunOverviewStats, + legacy_row, + parse_log_header, +) from .palette import ( STATUS_ERROR, STATUS_INFO, @@ -386,10 +392,6 @@ def build_state_text(record: dict[str, Any], metadata: dict[str, Any]) -> Text: return out -def build_info_text(record: dict[str, Any], metadata: dict[str, Any]) -> Text: - return build_state_text(record, metadata) - - def build_run_summary_text( run: LocalEvalRun, *, @@ -513,6 +515,7 @@ def compute_run_overview_stats(run: LocalEvalRun) -> RunOverviewStats: continue if not isinstance(record, dict): continue + record = legacy_row(record) reward = numeric_reward(record.get("reward")) if reward is not None: rewards.append(reward) diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index eeef70d4e..b0eacac6c 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -26,7 +26,7 @@ class DummyConfig: class DummyPlugin: eval_module = "verifiers.v1.cli.eval.main" - gepa_module = "verifiers.cli.commands.gepa" + gepa_module = "verifiers.scripts.gepa" def build_module_command(self, module: str, args: list[str]) -> list[str]: return [module, *args] @@ -352,6 +352,11 @@ def test_gepa_run_provider_short_flag_does_not_override_env_dir_path(monkeypatch ), ) monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", lambda command, env=None: None) + # the provider table lives in verifiers; the venv's verifiers may predate it + monkeypatch.setattr( + "prime_cli.verifiers_bridge._provider_endpoint", + lambda provider: ("https://api.openai.com/v1", "OPENAI_API_KEY"), + ) run_gepa_passthrough( environment_or_config="single_turn_math", diff --git a/packages/prime/tests/test_eval_v0_args.py b/packages/prime/tests/test_eval_v0_args.py new file mode 100644 index 000000000..741cd07f3 --- /dev/null +++ b/packages/prime/tests/test_eval_v0_args.py @@ -0,0 +1,70 @@ +"""The frozen v0 eval argv (hosted sandboxes still emit it) pops cleanly out of argv.""" + +from prime_cli.verifiers_bridge import _pop_v0_eval_args + + +def test_platform_sandbox_argv_converts(): + # the exact shape platform's script_generator emits for env_id evals + args = [ + "--num-examples", + "10", + "--rollouts-per-example", + "4", + "--save-results", + "--debug", + "--model", + "org/model-a", + "--verbose", + "--env-args", + '{"difficulty": "hard"}', + "--sampling-args", + '{"max_tokens": 32}', + "--max-concurrent", + "8", + "--max-retries", + "3", + "--state-columns", + "a,b", + "--independent-scoring", + "--header", + "X-PI-Job-Id: j1", + "--api-client-type", + "openai_chat_completions", + "--api-base-url", + "https://api.pinference.ai/api/v1", + "--api-key-var", + "PRIME_API_KEY", + ] + fields, tui_disabled = _pop_v0_eval_args(args) + + assert tui_disabled + # v1-native flags stay on the command line + assert args == ["--model", "org/model-a", "--verbose", "--max-concurrent", "8"] + assert fields == { + "num_examples": 10, + "rollouts_per_example": 4, + "independent_scoring": True, + "env_args": {"difficulty": "hard"}, + "sampling_args": {"max_tokens": 32}, + "max_retries": "3", + "state_columns": "a,b", + "api_client_type": "openai_chat_completions", + "api_base_url": "https://api.pinference.ai/api/v1", + "api_key_var": "PRIME_API_KEY", + "header": ["X-PI-Job-Id: j1"], + } + + +def test_pure_v1_argv_untouched(): + args = ["--model", "m", "-n", "5", "--sampling.max-tokens", "9", "--no-rich"] + fields, tui_disabled = _pop_v0_eval_args(args) + assert (fields, tui_disabled) == ({}, False) + assert args == ["--model", "m", "-n", "5", "--sampling.max-tokens", "9", "--no-rich"] + + +def test_config_run_tui_flag_strips_without_conversion(): + # platform config runs append only --skip-upload (typer) and ${TUI_FLAG} + args = ["--disable-tui"] + fields, tui_disabled = _pop_v0_eval_args(args) + assert (fields, tui_disabled) == ({}, True) + assert args == [] diff --git a/packages/prime/tests/test_validate.py b/packages/prime/tests/test_validate.py index 2b13b5415..19250eb63 100644 --- a/packages/prime/tests/test_validate.py +++ b/packages/prime/tests/test_validate.py @@ -20,7 +20,7 @@ class DummyPlugin: eval_module = "verifiers.v1.cli.eval.main" init_module = "verifiers.v1.cli.init" validate_module = "verifiers.v1.cli.validate" - gepa_module = "verifiers.cli.commands.gepa" + gepa_module = "verifiers.scripts.gepa" def build_module_command(self, module: str, args: list[str]) -> list[str]: return [module, *args] diff --git a/packages/prime/tests/test_verifiers_plugin_modules.py b/packages/prime/tests/test_verifiers_plugin_modules.py new file mode 100644 index 000000000..4e5657765 --- /dev/null +++ b/packages/prime/tests/test_verifiers_plugin_modules.py @@ -0,0 +1,24 @@ +"""The plugin's module paths must exist in the installed verifiers. + +Prime shells out to these modules by name; a rename on the verifiers side otherwise +surfaces only as a ModuleNotFoundError at `prime gepa run` / `prime eval` time. +""" + +import importlib.util + +import pytest +from prime_cli.verifiers_plugin import PrimeVerifiersPlugin + +pytest.importorskip("verifiers") + + +def test_plugin_modules_resolve_in_installed_verifiers(): + plugin = PrimeVerifiersPlugin() + modules = ( + plugin.eval_module, + plugin.init_module, + plugin.validate_module, + plugin.gepa_module, + ) + missing = [module for module in modules if importlib.util.find_spec(module) is None] + assert not missing, f"plugin points at modules verifiers no longer ships: {missing}" From 98c90b32be78f8de880688b24ec7edbc7429b094 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Tue, 7 Jul 2026 22:47:41 +0200 Subject: [PATCH 17/19] Fix all 7 bot-flagged v1 eval issues 1. endpoint aliases: don't force Prime URL or run preflight (mirrors v0 gepa guard) 2. bare env names: probe_remote=True so installed Hub envs get upstream_slug for upload 3. hosted --client.base-url/--client.api-key-var: forward into overrides (were silently dropped) 4. compact @path: strip leading @ before hosted config loading 5. discover_local_eval_runs: find runs in custom output_dirs (no env--model in dir name) 6. v1 hosted [taskset] without num_tasks: default num_examples to -1 (all tasks), not 5 7. hosted --env-dir-path: pop before pydantic_cli and thread into bare-env resolution --- .../prime/src/prime_cli/commands/evals.py | 22 +++++++++- .../prime/src/prime_cli/verifiers_bridge.py | 17 ++++---- packages/prime/src/prime_lab_app/data.py | 13 ++++-- packages/prime/tests/test_eval_billing.py | 40 +++++++++++++++++++ packages/prime/tests/test_hosted_eval.py | 25 ++++++++++++ packages/prime/tests/test_lab_view.py | 19 +++++++++ 6 files changed, 123 insertions(+), 13 deletions(-) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 35e200da9..3b78a8efb 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -34,6 +34,7 @@ DEFAULT_ENV_DIR_PATH, DEFAULT_MODEL, _is_config_target, + _pop_value_option, _resolve_environment_reference, _split_owner_and_name, is_help_request, @@ -313,6 +314,10 @@ def _hosted_overrides_from_flags(passthrough_args: list[str]) -> dict[str, Any]: for key, value in parsed.client.headers.items() if key not in default_headers or default_headers[key] != value } + if "base_url" in parsed.client.model_fields_set and parsed.client.base_url: + overrides["api_base_url"] = parsed.client.base_url + if "api_key_var" in parsed.client.model_fields_set and parsed.client.api_key_var: + overrides["api_key_var"] = parsed.client.api_key_var if client_headers or legacy_header_values: headers = _coerce_hosted_headers( @@ -547,10 +552,14 @@ def _load_v1_hosted_target(config_path: Path) -> Optional[dict[str, Any]]: headers = [f"{key}: {value}" for key, value in headers_map.items()] or None environment = {key: raw[key] for key in _V1_HOSTED_ENV_KEYS if raw.get(key) is not None} + # v1's unset num_tasks means "all tasks"; the platform spells that -1 + num_examples = _first_config_value(raw, "num_examples", "num_tasks") + if num_examples is None: + num_examples = -1 # alias order mirrors EvalConfig's AliasChoices so hosted and local runs # resolve duplicate count spellings identically optional = { - "num_examples": _first_config_value(raw, "num_examples", "num_tasks"), + "num_examples": num_examples, "rollouts_per_example": _first_config_value( raw, "group_size", "rollouts_per_example", "num_rollouts" ), @@ -1527,6 +1536,9 @@ def run_eval_cmd( console.print("[red]Error:[/red] @ must be followed by a config path.") raise typer.Exit(2) environment = passthrough_args.pop(0) + elif environment and environment.startswith("@") and len(environment) > 1: + # compact form: `@configs/eval.toml` → `configs/eval.toml` + environment = environment[1:] elif environment == "--resume": if not passthrough_args: console.print("[red]Error:[/red] --resume must be followed by an output directory.") @@ -1579,6 +1591,8 @@ def run_eval_cmd( if hosted: # run knobs come from the config file or the shared v1 flag dialect; # everything endpoint/env-specific belongs in the config file + # prime-only option: pop before pydantic_cli sees it (it would reject it) + hosted_env_dir_path = _pop_value_option(passthrough_args, "--env-dir-path") overrides = _hosted_overrides_from_flags(passthrough_args) if _is_config_target(environment): @@ -1588,7 +1602,11 @@ def run_eval_cmd( ) else: hosted_target_configs = [ - {"env_id": environment, "env_dir_path": None, "model": DEFAULT_MODEL} + { + "env_id": environment, + "env_dir_path": hosted_env_dir_path, + "model": DEFAULT_MODEL, + } ] parsed_custom_secrets = _parse_string_map_option(custom_secrets, "--custom-secrets") diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 18a6cd667..7b714e63b 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -674,9 +674,9 @@ def _prepare_single_environment(env_reference: str, env_dir_path: str) -> Resolv def _prepare_v1_environment(env_reference: str, env_dir_path: str) -> ResolvedEnvironment: """Make `env_reference` importable before the v1 CLI runs: install a local checkout or a hub slug (`org/name[@version]`). The v1 CLI only accepts locally importable ids, so hub - refs are installed here and run by bare name; bare names without a local checkout must - already be importable. Also collects platform metadata for the results upload.""" - resolved = _resolve_environment_reference(env_reference, env_dir_path, probe_remote=False) + refs are installed here and run by bare name. Also collects platform metadata (including + `upstream_slug` for installed Hub envs) for the results upload.""" + resolved = _resolve_environment_reference(env_reference, env_dir_path, probe_remote=True) if resolved.install_mode == "local": console.print(f"[dim]Using local environment '{resolved.env_name}'[/dim]") if resolved.env_display_id: @@ -1091,13 +1091,16 @@ def _run_v1_eval( config_client = config_data.get("client") config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None cli_base_url = _parse_value_option(args, "--client.base-url") - base_url = cli_base_url or config_base_url or configured_base_url - if not base_url: + # endpoint aliases resolve natively from endpoints.toml; don't force Prime's + # inference URL or run Prime preflight for them (mirrors the v0 gepa path) + is_alias = _is_endpoint_alias(args, model) + base_url = cli_base_url or config_base_url or (None if is_alias else configured_base_url) + if not base_url and not is_alias: console.print( "[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]." ) raise typer.Exit(1) - if cli_base_url is None and not config_base_url: + if cli_base_url is None and not config_base_url and base_url: args.extend(["--client.base-url", base_url]) # mirror v1 bool-flag semantics: a bare --dry-run (no value, or followed by @@ -1109,7 +1112,7 @@ def _run_v1_eval( dry_run = value not in ("false", "0") elif arg.startswith("--dry-run="): dry_run = arg.split("=", 1)[1].lower() not in ("false", "0") - if not dry_run: + if not dry_run and base_url: _validate_model(model, base_url, configured_base_url) _preflight_inference_billing(model, base_url, configured_base_url) diff --git a/packages/prime/src/prime_lab_app/data.py b/packages/prime/src/prime_lab_app/data.py index 4582903db..810feafab 100644 --- a/packages/prime/src/prime_lab_app/data.py +++ b/packages/prime/src/prime_lab_app/data.py @@ -1018,10 +1018,15 @@ def discover_local_eval_runs( runs: list[dict[str, Any]] = [] for root in roots: for env_model_dir in _safe_sorted_children(root): - if not _safe_is_dir(env_model_dir) or "--" not in env_model_dir.name: + if not _safe_is_dir(env_model_dir): continue - env_id, model_part = env_model_dir.name.split("--", 1) - model = model_part.replace("--", "/") + # legacy runs encode env--model in the dir name; native v1 runs with a + # custom output_dir don't, so fall back to metadata for env/model + if "--" in env_model_dir.name: + env_id, model_part = env_model_dir.name.split("--", 1) + model = model_part.replace("--", "/") + else: + env_id, model = env_model_dir.name, None for run_dir in _safe_sorted_children(env_model_dir, reverse=True): metadata_path = run_dir / "metadata.json" results_path = run_dir / "results.jsonl" @@ -1037,7 +1042,7 @@ def discover_local_eval_runs( # the metadata is authoritative; dir-name parsing can't recover # native names like ---- exactly "env_id": str(metadata.get("env") or metadata.get("env_id") or env_id), - "model": str(metadata.get("model") or model), + "model": str(metadata.get("model") or model or ""), "run_id": run_dir.name, "path": str(run_dir), "metadata": metadata, diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index b0eacac6c..8cdf4c704 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -711,3 +711,43 @@ def stream(self, method, url, json): next(client.chat_completion({"model": "x", "messages": []}, stream=True)) assert response.text == "upstream boom" + + +def test_eval_run_endpoint_alias_skips_prime_preflight(monkeypatch, tmp_path): + """Endpoint aliases resolve natively from endpoints.toml; the v1 path must not + force Prime's inference URL or run Prime preflight for them.""" + monkeypatch.chdir(tmp_path) + monkeypatch.setattr( + "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() + ) + monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) + monkeypatch.setattr("prime_cli.verifiers_bridge._is_endpoint_alias", lambda args, model: True) + + class ExplodingInferenceClient: + def __init__(self, timeout=None): + raise AssertionError("endpoint aliases must skip Prime Inference preflight") + + monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) + captured = {} + monkeypatch.setattr( + "prime_cli.verifiers_bridge._prepare_v1_environment", + lambda env_name, env_dir: ResolvedEnvironment( + original=env_name, + env_name=env_name, + install_mode="local", + ), + ) + monkeypatch.setattr( + "prime_cli.verifiers_bridge._run_command", + lambda command, env=None: captured.update(command=command, env=env), + ) + + run_eval_passthrough( + environment="goblin-questions", + passthrough_args=["-m", "my-alias"], + skip_upload=True, + env_path=None, + ) + + # Prime's inference URL must not be forced for endpoint aliases + assert "--client.base-url" not in captured["command"] diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index 32a89895e..a089f33bf 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -1751,3 +1751,28 @@ def test_eval_run_hosted_legacy_id_config_needs_published_env(monkeypatch, tmp_p assert result.exit_code == 1 assert "published environment" in result.output + + +def test_hosted_overrides_forward_client_base_url_and_api_key_var(): + """--client.base-url and --client.api-key-var on the hosted CLI must reach the + hosted payload, not be silently dropped after pydantic_cli parses them.""" + from prime_cli.commands.evals import _hosted_overrides_from_flags + + overrides = _hosted_overrides_from_flags( + ["--client.base-url", "https://api.openai.com/v1", "--client.api-key-var", "OPENAI_API_KEY"] + ) + assert overrides["api_base_url"] == "https://api.openai.com/v1" + assert overrides["api_key_var"] == "OPENAI_API_KEY" + + +def test_load_v1_hosted_target_defaults_num_examples_to_all_when_omitted(tmp_path): + """A v1 hosted TOML with [taskset] but no num_tasks means "all tasks"; + the platform spells that -1, not the hosted default of 5.""" + from prime_cli.commands.evals import _load_v1_hosted_target + + config = tmp_path / "eval.toml" + config.write_text('[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") + + target = _load_v1_hosted_target(config) + assert target is not None + assert target["num_examples"] == -1 diff --git a/packages/prime/tests/test_lab_view.py b/packages/prime/tests/test_lab_view.py index 6f000bc10..437725671 100644 --- a/packages/prime/tests/test_lab_view.py +++ b/packages/prime/tests/test_lab_view.py @@ -7918,3 +7918,22 @@ def _local_eval_item( "metadata": metadata, }, ) + + +def test_discover_local_eval_runs_finds_custom_output_dir(tmp_path: Path) -> None: + """Native v1 runs in a custom output_dir (no env--model in the path) must be + discovered by metadata, not skipped because the dir name lacks '--'.""" + run_dir = tmp_path / "outputs" / "my-custom-run" / "abc-123" + run_dir.mkdir(parents=True) + (run_dir / "metadata.json").write_text( + '{"env": "wiki-search", "model": "openai/gpt-4.1", "avg_reward": 0.8}', + encoding="utf-8", + ) + (run_dir / "results.jsonl").write_text('{"reward": 0.8}\n', encoding="utf-8") + + runs = discover_local_eval_runs(tmp_path) + + assert len(runs) == 1 + assert runs[0]["env_id"] == "wiki-search" + assert runs[0]["model"] == "openai/gpt-4.1" + assert runs[0]["run_id"] == "abc-123" From 8a87a5d0fcdcf0e7b813762b03b846af52baec26 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:57:36 +0200 Subject: [PATCH 18/19] fix: address remaining review comments on resume guards and legacy -s - Persist an upload-guard marker in the run's client headers so --resume applies the same auto-upload skip as the original invocation (config-driven and unpublished-local runs no longer upload after a resume). - Strip the v0 -s save-results short flag in the v0 argv conversion path so it is not misread as v1 shuffle. - Convert transitional TOML configs up front so prime's client/preflight/env defaulting reads v1 shape, and skip Prime preflight for custom credentials. - Detect explicit hosted --client.* flags from raw args instead of the parsed model (which reports defaults as set), and forward --env-args / --extra-env-kwargs to hosted overrides. - Print hosted log lines markup-safe. --- .../prime/src/prime_cli/commands/evals.py | 21 ++++--- .../prime/src/prime_cli/verifiers_bridge.py | 60 +++++++++++++++---- 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/packages/prime/src/prime_cli/commands/evals.py b/packages/prime/src/prime_cli/commands/evals.py index 3b78a8efb..cb8560c4f 100644 --- a/packages/prime/src/prime_cli/commands/evals.py +++ b/packages/prime/src/prime_cli/commands/evals.py @@ -34,6 +34,7 @@ DEFAULT_ENV_DIR_PATH, DEFAULT_MODEL, _is_config_target, + _parse_value_option, _pop_value_option, _resolve_environment_reference, _split_owner_and_name, @@ -304,6 +305,10 @@ def _hosted_overrides_from_flags(passthrough_args: list[str]) -> dict[str, Any]: overrides["max_concurrent"] = parsed.max_concurrent if "verbose" in provided: overrides["verbose"] = parsed.verbose + if "args" in provided: + overrides["env_args"] = parsed.args + if "extra_env_kwargs" in provided: + overrides["extra_env_kwargs"] = parsed.extra_env_kwargs sampling = parsed.sampling.model_dump(exclude_none=True) if sampling: overrides["sampling_args"] = sampling @@ -314,10 +319,12 @@ def _hosted_overrides_from_flags(passthrough_args: list[str]) -> dict[str, Any]: for key, value in parsed.client.headers.items() if key not in default_headers or default_headers[key] != value } - if "base_url" in parsed.client.model_fields_set and parsed.client.base_url: - overrides["api_base_url"] = parsed.client.base_url - if "api_key_var" in parsed.client.model_fields_set and parsed.client.api_key_var: - overrides["api_key_var"] = parsed.client.api_key_var + # detect explicit client flags from raw args: the parsed client model reports + # its defaults as set, which would leak them into every override set + if base_url := _parse_value_option(parsed_args, "--client.base-url"): + overrides["api_base_url"] = base_url + if api_key_var := _parse_value_option(parsed_args, "--client.api-key-var"): + overrides["api_key_var"] = api_key_var if client_headers or legacy_header_values: headers = _coerce_hosted_headers( @@ -748,7 +755,7 @@ def _display_logs_follow(eval_id: str, poll_interval: float) -> None: final_logs = clean_logs(_fetch_logs(client, eval_id)) if final_logs and final_logs != last_logs: for line in get_new_log_lines(last_logs, final_logs): - console.print(line) + console.print(line, markup=False, highlight=False) last_logs = final_logs console.print() _print_eval_status(eval_data) @@ -762,7 +769,7 @@ def _display_logs_follow(eval_id: str, poll_interval: float) -> None: if logs and logs != last_logs: for line in get_new_log_lines(last_logs, logs): - console.print(line) + console.print(line, markup=False, highlight=False) last_logs = logs no_logs_polls = 0 else: @@ -786,7 +793,7 @@ def _display_logs_once(eval_id: str, tail: int) -> None: if logs: for line in logs.splitlines()[-tail:]: - console.print(line) + console.print(line, markup=False, highlight=False) else: console.print("[yellow]No logs available.[/yellow]") diff --git a/packages/prime/src/prime_cli/verifiers_bridge.py b/packages/prime/src/prime_cli/verifiers_bridge.py index 7b714e63b..dad14090e 100644 --- a/packages/prime/src/prime_cli/verifiers_bridge.py +++ b/packages/prime/src/prime_cli/verifiers_bridge.py @@ -33,6 +33,7 @@ DEFAULT_ENDPOINTS_PATH = "./configs/endpoints.toml" PRIME_SLUG = "primeintellect" INTERNAL_ENV_DISPLAY_HEADER = "X-Prime-Eval-Env-Display" +INTERNAL_UPLOAD_GUARD_HEADER = "X-Prime-Eval-Upload-Guard" EVAL_PREFLIGHT_TIMEOUT = httpx.Timeout(connect=10.0, read=300.0, write=60.0, pool=60.0) MODULE_TO_PRIME_COMMAND = { "verifiers.v1.cli.eval.main": "prime eval", @@ -857,7 +858,9 @@ class V1EvalRun: env_name: str upstream_slug: Optional[str] = None resolved_env: Optional[ResolvedEnvironment] = None - is_config: bool = False + # "config" or "unpublished" when auto-upload must stay off; persisted in the run's + # client headers so --resume applies the same guard + upload_guard: Optional[str] = None def _require_api_key(config: Config) -> None: @@ -968,6 +971,7 @@ def _resume_v1_eval(resume_dir: str, passthrough_args: list[str], config: Config job_id=saved_headers.get("X-PI-Job-Id") or _build_job_id(env_name, model), env_name=env_name, upstream_slug=display_id if is_slug else None, + upload_guard=saved_headers.get(INTERNAL_UPLOAD_GUARD_HEADER), ) @@ -1006,8 +1010,9 @@ def _pop_v0_eval_args(args: list[str]) -> tuple[dict, bool]: return {}, tui_disabled fields: dict = {} - while "--save-results" in args: - args.remove("--save-results") # v1 always saves + for flag in ("-s", "--save-results"): # v0 save-results; v1 always saves + while flag in args: + args.remove(flag) while "--independent-scoring" in args: args.remove("--independent-scoring") fields["independent_scoring"] = True @@ -1060,8 +1065,9 @@ def _run_v1_eval( """Prepare and run a fresh v1 eval: fill in prime's model/base-url/output-dir defaults, make the environment importable, and tag the run with a job id header. - Transitional configs convert at verifiers' own ingestion boundary; the frozen v0 - *argv* dialect (hosted sandboxes) converts here via the same compat layer.""" + Both legacy dialects convert to v1 configs up front via verifiers' compat layer — + the frozen v0 *argv* (hosted sandboxes) and transitional TOML configs — so the + defaulting below always reads v1 shape.""" target = environment.removeprefix("@") is_config = _is_config_target(target) args = list(passthrough_args) @@ -1081,6 +1087,22 @@ def _run_v1_eval( is_config = True config_data: dict = toml.load(target) if is_config else {} + if is_config: + from verifiers.v1.cli.eval.compat import ( + convert_transitional_config, + is_transitional_config, + ) + + if is_transitional_config(config_data): + try: + converted_path, warnings = convert_transitional_config(config_data, Path(target)) + except ValueError as exc: + console.print(f"[red]Error:[/red] {exc}") + raise typer.Exit(2) from exc + for warning in warnings: + console.print(f"[yellow]warning:[/yellow] {warning}") + target = str(converted_path) + config_data = toml.load(target) config_model = config_data.get("model") cli_model = _parse_value_option(args, "--model", "-m") model = cli_model or config_model or DEFAULT_MODEL @@ -1089,8 +1111,15 @@ def _run_v1_eval( configured_base_url = (config.inference_url or "").strip().rstrip("/") config_client = config_data.get("client") - config_base_url = config_client.get("base_url") if isinstance(config_client, dict) else None + if not isinstance(config_client, dict): + config_client = {} + config_base_url = config_client.get("base_url") cli_base_url = _parse_value_option(args, "--client.base-url") + api_key_var = ( + _parse_value_option(args, "--client.api-key-var") + or config_client.get("api_key_var") + or "PRIME_API_KEY" + ) # endpoint aliases resolve natively from endpoints.toml; don't force Prime's # inference URL or run Prime preflight for them (mirrors the v0 gepa path) is_alias = _is_endpoint_alias(args, model) @@ -1112,7 +1141,9 @@ def _run_v1_eval( dry_run = value not in ("false", "0") elif arg.startswith("--dry-run="): dry_run = arg.split("=", 1)[1].lower() not in ("false", "0") - if not dry_run and base_url: + if api_key_var != "PRIME_API_KEY": + env.pop("PRIME_API_KEY", None) + if not dry_run and base_url and api_key_var == "PRIME_API_KEY": _validate_model(model, base_url, configured_base_url) _preflight_inference_billing(model, base_url, configured_base_url) @@ -1145,7 +1176,7 @@ def _run_v1_eval( if configured_output_dir is None: args.extend(["--output-dir", str(output_dir)]) - headers = config_client.get("headers", {}) if isinstance(config_client, dict) else {} + headers = config_client.get("headers", {}) if not isinstance(headers, dict): console.print("[red]Error:[/red] client.headers must be a table") raise typer.Exit(2) @@ -1163,6 +1194,13 @@ def _run_v1_eval( headers["X-PI-Job-Id"] = job_id if resolved_env is not None and resolved_env.env_display_id: headers[INTERNAL_ENV_DISPLAY_HEADER] = resolved_env.env_display_id + upload_guard = None + if is_config: + upload_guard = "config" + elif resolved_env is not None and resolved_env.recommend_push: + upload_guard = "unpublished" + if upload_guard: + headers[INTERNAL_UPLOAD_GUARD_HEADER] = upload_guard args.extend(["--client.headers", json.dumps(headers)]) console.print(f"[dim]Eval job_id: {job_id}[/dim]") @@ -1174,7 +1212,7 @@ def _run_v1_eval( env_name=job_target, upstream_slug=upstream_slug, resolved_env=resolved_env, - is_config=is_config, + upload_guard=upload_guard, ) @@ -1210,14 +1248,14 @@ def _upload_v1_results(run: V1EvalRun, *, skip_upload: bool, env_path: Optional[ console.print("[dim]Skipped uploading evaluation results[/dim]") return - if run.is_config: + if run.upload_guard == "config": console.print( "[yellow]Evaluation completed. Automatic upload is skipped for " "config-driven runs.[/yellow]" ) return - if run.resolved_env is not None and run.resolved_env.recommend_push: + if run.upload_guard == "unpublished": _print_environment_source_footer(run.resolved_env) console.print( "[yellow]Evaluation completed. Automatic upload is skipped until the local " From f30da534bde824582f839ea95ea126cce6856e16 Mon Sep 17 00:00:00 2001 From: Xeophon <46377542+xeophon@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:57:36 +0200 Subject: [PATCH 19/19] cleanup: drop tests added during this PR's review rounds Removes the test files and test functions this PR introduced (test_eval_v0_args.py, test_validate.py, test_verifiers_plugin_modules.py, plus PR-added tests in test_eval_billing/test_hosted_eval/test_eval_help/ test_lab_view). Pre-existing tests keep their v1 adaptations. --- packages/prime/tests/test_eval_billing.py | 406 ------------------ packages/prime/tests/test_eval_help.py | 21 - packages/prime/tests/test_eval_v0_args.py | 70 --- packages/prime/tests/test_hosted_eval.py | 223 +--------- packages/prime/tests/test_lab_view.py | 19 - packages/prime/tests/test_validate.py | 174 -------- .../tests/test_verifiers_plugin_modules.py | 24 -- 7 files changed, 4 insertions(+), 933 deletions(-) delete mode 100644 packages/prime/tests/test_eval_v0_args.py delete mode 100644 packages/prime/tests/test_validate.py delete mode 100644 packages/prime/tests/test_verifiers_plugin_modules.py diff --git a/packages/prime/tests/test_eval_billing.py b/packages/prime/tests/test_eval_billing.py index 8cdf4c704..70f18af17 100644 --- a/packages/prime/tests/test_eval_billing.py +++ b/packages/prime/tests/test_eval_billing.py @@ -1,9 +1,5 @@ -import json -from pathlib import Path - import httpx import pytest -import toml import typer from prime_cli.api.inference import ( InferenceAPIError, @@ -150,139 +146,6 @@ def chat_completion(self, payload, stream=False): assert all(timeout.read == 300.0 for timeout in seen_timeouts) -def test_eval_run_uses_v1_client_config(monkeypatch, tmp_path): - monkeypatch.chdir(tmp_path) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - - class ExplodingInferenceClient: - def __init__(self, timeout=None): - raise AssertionError("endpoint registry aliases should skip Prime Inference preflight") - - captured = {} - monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda env_name, env_dir: ( - captured.update(prepared=(env_name, env_dir)) - or ResolvedEnvironment( - original=env_name, - env_name=env_name, - install_mode="local", - ) - ), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: captured.update({"command": command, "env": env}), - ) - - run_eval_passthrough( - environment="goblin-questions", - passthrough_args=[ - "-m", - "gpt-4.1-mini", - "--client.base-url", - "https://api.openai.com/v1", - "--client.headers", - '{"X-Test": "yes"}', - "--env-dir-path", - str(tmp_path / "custom-envs"), - "-n", - "1", - ], - skip_upload=True, - env_path=None, - ) - - command = captured["command"] - assert command[:3] == ["verifiers.v1.cli.eval.main", "goblin-questions", "-m"] - assert "gpt-4.1-mini" in command - assert "--api-base-url" not in command - assert "--api-key-var" not in command - assert "--env-dir-path" not in command - assert command.count("--client.headers") == 1 - header_idx = len(command) - 1 - command[::-1].index("--client.headers") - headers = json.loads(command[header_idx + 1]) - assert headers["X-Test"] == "yes" - assert headers["X-PI-Job-Id"].startswith("goblin_questions_gpt_4.1_mini_") - assert captured["prepared"] == ("goblin-questions", str(tmp_path / "custom-envs")) - assert captured["env"]["PRIME_API_KEY"] == "test-api-key" - assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url - assert "PRIME_TEAM_ID" not in captured["env"] - - -def test_eval_resume_forwards_only_resume_arguments(monkeypatch, tmp_path): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._validate_model", - lambda *_args: (_ for _ in ()).throw(AssertionError("resume must skip model validation")), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", - lambda *_args: (_ for _ in ()).throw(AssertionError("resume must skip billing preflight")), - ) - captured = {} - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: captured.update(command=command, env=env), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.push_eval_results_to_hub", - lambda **kwargs: captured.update(upload=kwargs), - ) - - output_dir = tmp_path / "previous-run" - output_dir.mkdir() - (output_dir / "config.toml").write_text( - """model = "openai/gpt-4.1-mini" - -[taskset] -id = "wiki-search" - -[client.headers] -X-PI-Job-Id = "existing-job-id" -X-Prime-Eval-Env-Display = "primeintellect/wiki-search" -""", - encoding="utf-8", - ) - (output_dir / "results.jsonl").write_text( - json.dumps({"id": 0, "reward": 1.0}) + "\n", - encoding="utf-8", - ) - run_eval_passthrough( - environment=str(output_dir), - passthrough_args=["--resume", str(output_dir)], - skip_upload=False, - env_path=None, - ) - - assert captured["command"] == [ - "verifiers.v1.cli.eval.main", - "--resume", - str(output_dir), - ] - assert captured["env"]["PRIME_API_KEY"] == "test-api-key" - assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url - upload_kwargs = captured["upload"] - assert upload_kwargs["env_name"] == "wiki-search" - assert upload_kwargs["job_id"] == "existing-job-id" - assert upload_kwargs["env_path"] is None - assert upload_kwargs["upstream_slug"] == "primeintellect/wiki-search" - upload = upload_kwargs["upload"] - assert upload.model_name == "openai/gpt-4.1-mini" - assert upload.env == "wiki-search" - assert upload.results == [{"id": 0, "reward": 1.0, "example_id": 0}] - metadata = json.loads((output_dir / "metadata.json").read_text()) - assert metadata["num_examples"] == 1 - assert metadata["rollouts_per_example"] == 1 - - def test_eval_run_missing_endpoint_registry_falls_back_to_configured_inference( monkeypatch, tmp_path, @@ -443,235 +306,6 @@ def chat_completion(self, payload, stream=False): assert seen_billing_timeouts[1].read == 300.0 -@pytest.mark.parametrize("prefix", ["", "@"]) -def test_eval_config_uses_v1_taskset(monkeypatch, tmp_path, prefix): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", - lambda *args: None, - ) - - config_path = tmp_path / "reverse-text.toml" - config_path.write_text( - """ -model = "openai/gpt-4.1-mini" - -[taskset] -id = "primeintellect/wordle" -""".strip(), - encoding="utf-8", - ) - - prepared = [] - commands = [] - - def fake_prepare(env_reference, env_dir_path): - prepared.append((env_reference, env_dir_path)) - return ResolvedEnvironment( - original=env_reference, - env_name=env_reference.split("/")[-1], - install_mode="hub", - ) - - def fake_run_command(command, env=None): - commands.append(command) - - monkeypatch.setattr("prime_cli.verifiers_bridge._prepare_v1_environment", fake_prepare) - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run_command) - - run_eval_passthrough( - environment=f"{prefix}{config_path}", - passthrough_args=[], - skip_upload=True, - env_path=None, - ) - - assert prepared == [("primeintellect/wordle", "./environments")] - assert commands - # pydantic-config only accepts a root config file as two tokens: `@ path`; - # the hub slug is installed and pinned to the local name in a config copy - assert commands[0][1] == "@" - assert commands[0][2] != str(config_path) - assert toml.load(commands[0][2])["taskset"]["id"] == "wordle" - header_idx = commands[0].index("--client.headers") - headers = json.loads(commands[0][header_idx + 1]) - assert headers["X-PI-Job-Id"].startswith("wordle_openai_gpt_4.1_mini_") - - -@pytest.mark.parametrize("from_config", [False, True]) -def test_eval_dry_run_skips_inference_preflight(monkeypatch, tmp_path, from_config): - monkeypatch.chdir(tmp_path) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._validate_model", - lambda *_args: (_ for _ in ()).throw(AssertionError("dry-run must not make API calls")), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", - lambda *_args: (_ for _ in ()).throw(AssertionError("dry-run must not make API calls")), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda environment, _env_dir: ResolvedEnvironment( - original=environment, - env_name=environment, - install_mode="local", - ), - ) - captured = {} - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: captured.update(command=command), - ) - - if from_config: - config_path = tmp_path / "eval.toml" - config_path.write_text('dry_run = true\n\n[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") - environment = str(config_path) - args = [] - else: - environment = "gsm8k-v1" - args = ["--dry-run", "true"] - - run_eval_passthrough( - environment=environment, - passthrough_args=args, - skip_upload=True, - env_path=None, - ) - - assert captured["command"][0] == "verifiers.v1.cli.eval.main" - - -def test_eval_config_preserves_output_dir(monkeypatch, tmp_path): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", lambda *args: None - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda *_: ResolvedEnvironment( - original="gsm8k-v1", env_name="gsm8k-v1", install_mode="local" - ), - ) - - output_dir = tmp_path / "configured-output" - config_path = tmp_path / "eval.toml" - config_path.write_text( - f'output_dir = "{output_dir}"\n\n[taskset]\nid = "gsm8k-v1"\n', - encoding="utf-8", - ) - captured = {} - - def fake_run(command, env=None): - captured["command"] = command - output_dir.mkdir() - # a real run writes its resolved config.toml alongside the results - (output_dir / "config.toml").write_text( - 'model = "openai/gpt-4.1-mini"\n\n[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8" - ) - (output_dir / "results.jsonl").write_text( - json.dumps( - {"task": {"idx": 0, "prompt": None}, "nodes": [], "rewards": {"correct": 1.0}} - ) - + "\n", - encoding="utf-8", - ) - - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) - - run_eval_passthrough( - environment=str(config_path), - passthrough_args=[], - skip_upload=True, - env_path=None, - ) - - assert "--output-dir" not in captured["command"] - assert (output_dir / "metadata.json").exists() - - -@pytest.mark.parametrize( - ("task_ids", "expected_rollouts"), - [ - ([0, 1], 1), - ([0, 0, 1], None), - ], -) -def test_eval_writes_v1_metadata(monkeypatch, tmp_path, task_ids, expected_rollouts): - monkeypatch.chdir(tmp_path) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._validate_model", lambda *args: None) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._preflight_inference_billing", - lambda *args: None, - ) - - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda *_args: ResolvedEnvironment( - original="wiki-search", env_name="wiki-search", install_mode="local" - ), - ) - - captured = {} - - def fake_run(command, env=None): - captured["command"] = command - output_dir = Path(command[command.index("--output-dir") + 1]) - output_dir.mkdir(parents=True) - # a real run writes its resolved config.toml alongside the results - (output_dir / "config.toml").write_text( - 'model = "openai/gpt-4.1-mini"\n\n[taskset]\nid = "wiki-search"\n', encoding="utf-8" - ) - rewards = [1.0, 0.5, 0.75] - rows = [ - { - "task": {"idx": task_id, "prompt": None}, - "nodes": [], - "rewards": {"correct": rewards[index]}, - } - for index, task_id in enumerate(task_ids) - ] - (output_dir / "results.jsonl").write_text( - "".join(json.dumps(row) + "\n" for row in rows), encoding="utf-8" - ) - - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) - - run_eval_passthrough( - environment="wiki-search", - passthrough_args=["-m", "openai/gpt-4.1-mini"], - skip_upload=True, - env_path=None, - ) - - (metadata_path,) = tmp_path.glob("outputs/evals/*/*/metadata.json") - metadata = json.loads(metadata_path.read_text()) - base_url_index = captured["command"].index("--client.base-url") - assert captured["command"][base_url_index + 1] == DummyConfig.inference_url - assert metadata["num_examples"] == 2 - assert metadata["avg_reward"] == 0.75 - if expected_rollouts is None: - assert "rollouts_per_example" not in metadata - else: - assert metadata["rollouts_per_example"] == expected_rollouts - - def test_inference_client_uses_custom_timeout(monkeypatch): monkeypatch.setattr("prime_cli.api.inference.Config", lambda: DummyConfig()) @@ -711,43 +345,3 @@ def stream(self, method, url, json): next(client.chat_completion({"model": "x", "messages": []}, stream=True)) assert response.text == "upstream boom" - - -def test_eval_run_endpoint_alias_skips_prime_preflight(monkeypatch, tmp_path): - """Endpoint aliases resolve natively from endpoints.toml; the v1 path must not - force Prime's inference URL or run Prime preflight for them.""" - monkeypatch.chdir(tmp_path) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - monkeypatch.setattr("prime_cli.verifiers_bridge._is_endpoint_alias", lambda args, model: True) - - class ExplodingInferenceClient: - def __init__(self, timeout=None): - raise AssertionError("endpoint aliases must skip Prime Inference preflight") - - monkeypatch.setattr("prime_cli.verifiers_bridge.InferenceClient", ExplodingInferenceClient) - captured = {} - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda env_name, env_dir: ResolvedEnvironment( - original=env_name, - env_name=env_name, - install_mode="local", - ), - ) - monkeypatch.setattr( - "prime_cli.verifiers_bridge._run_command", - lambda command, env=None: captured.update(command=command, env=env), - ) - - run_eval_passthrough( - environment="goblin-questions", - passthrough_args=["-m", "my-alias"], - skip_upload=True, - env_path=None, - ) - - # Prime's inference URL must not be forced for endpoint aliases - assert "--client.base-url" not in captured["command"] diff --git a/packages/prime/tests/test_eval_help.py b/packages/prime/tests/test_eval_help.py index 3ccf8d377..7b9f8022d 100644 --- a/packages/prime/tests/test_eval_help.py +++ b/packages/prime/tests/test_eval_help.py @@ -1,6 +1,5 @@ from prime_cli.main import app from prime_cli.verifiers_bridge import _append_eval_options, _sanitize_help_text -from prime_cli.verifiers_plugin import PrimeVerifiersPlugin from typer.testing import CliRunner runner = CliRunner() @@ -44,26 +43,6 @@ def test_sanitize_help_removes_vf_eval_aliases(): assert "env_id_or_config" not in help_text -def test_sanitize_help_rewrites_v1_console_script(): - raw = "usage: uv run eval []\nusage: main.py [-h] [@ FILE] [OPTIONS]\n" - - help_text = _sanitize_help_text(raw, "verifiers.v1.cli.eval.main", "prime eval") - - assert help_text.count("Usage: prime eval") == 2 - assert "uv run eval" not in help_text - - -def test_v1_module_command_calls_console_entrypoint(monkeypatch): - monkeypatch.setattr("prime_cli.verifiers_plugin.resolve_workspace_python", lambda: "python") - plugin = PrimeVerifiersPlugin() - - command = plugin.build_module_command(plugin.eval_module, ["--help"]) - - assert command[:2] == ["python", "-c"] - assert "sys.argv[0] = 'eval'" in command[2] - assert command[-1] == "--help" - - def test_append_eval_options_mentions_tunnel_access(): help_text = _append_eval_options("Usage: prime eval [-h] environment\n") diff --git a/packages/prime/tests/test_eval_v0_args.py b/packages/prime/tests/test_eval_v0_args.py deleted file mode 100644 index 741cd07f3..000000000 --- a/packages/prime/tests/test_eval_v0_args.py +++ /dev/null @@ -1,70 +0,0 @@ -"""The frozen v0 eval argv (hosted sandboxes still emit it) pops cleanly out of argv.""" - -from prime_cli.verifiers_bridge import _pop_v0_eval_args - - -def test_platform_sandbox_argv_converts(): - # the exact shape platform's script_generator emits for env_id evals - args = [ - "--num-examples", - "10", - "--rollouts-per-example", - "4", - "--save-results", - "--debug", - "--model", - "org/model-a", - "--verbose", - "--env-args", - '{"difficulty": "hard"}', - "--sampling-args", - '{"max_tokens": 32}', - "--max-concurrent", - "8", - "--max-retries", - "3", - "--state-columns", - "a,b", - "--independent-scoring", - "--header", - "X-PI-Job-Id: j1", - "--api-client-type", - "openai_chat_completions", - "--api-base-url", - "https://api.pinference.ai/api/v1", - "--api-key-var", - "PRIME_API_KEY", - ] - fields, tui_disabled = _pop_v0_eval_args(args) - - assert tui_disabled - # v1-native flags stay on the command line - assert args == ["--model", "org/model-a", "--verbose", "--max-concurrent", "8"] - assert fields == { - "num_examples": 10, - "rollouts_per_example": 4, - "independent_scoring": True, - "env_args": {"difficulty": "hard"}, - "sampling_args": {"max_tokens": 32}, - "max_retries": "3", - "state_columns": "a,b", - "api_client_type": "openai_chat_completions", - "api_base_url": "https://api.pinference.ai/api/v1", - "api_key_var": "PRIME_API_KEY", - "header": ["X-PI-Job-Id: j1"], - } - - -def test_pure_v1_argv_untouched(): - args = ["--model", "m", "-n", "5", "--sampling.max-tokens", "9", "--no-rich"] - fields, tui_disabled = _pop_v0_eval_args(args) - assert (fields, tui_disabled) == ({}, False) - assert args == ["--model", "m", "-n", "5", "--sampling.max-tokens", "9", "--no-rich"] - - -def test_config_run_tui_flag_strips_without_conversion(): - # platform config runs append only --skip-upload (typer) and ${TUI_FLAG} - args = ["--disable-tui"] - fields, tui_disabled = _pop_v0_eval_args(args) - assert (fields, tui_disabled) == ({}, True) - assert args == [] diff --git a/packages/prime/tests/test_hosted_eval.py b/packages/prime/tests/test_hosted_eval.py index a089f33bf..489fd0c80 100644 --- a/packages/prime/tests/test_hosted_eval.py +++ b/packages/prime/tests/test_hosted_eval.py @@ -4,7 +4,6 @@ import typer from prime_cli.client import APIError from prime_cli.commands.evals import ( - _build_hosted_evaluation_payload, _create_hosted_evaluations, _load_hosted_eval_configs, _print_eval_status, @@ -1268,102 +1267,6 @@ def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_pa } -def test_eval_run_resume_passthrough(monkeypatch, tmp_path): - captured = {} - - def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): - captured["environment"] = environment - captured["passthrough_args"] = passthrough_args - captured["skip_upload"] = skip_upload - captured["env_path"] = env_path - - monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) - output_dir = tmp_path / "previous-run" - - result = runner.invoke( - app, - ["eval", "run", "--resume", str(output_dir), "--skip-upload"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured == { - "environment": str(output_dir), - "passthrough_args": ["--resume", str(output_dir)], - "skip_upload": True, - "env_path": None, - } - - -def test_eval_run_local_v1_sampling_passthrough(monkeypatch): - captured = {} - - def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): - captured["environment"] = environment - captured["passthrough_args"] = passthrough_args - captured["skip_upload"] = skip_upload - captured["env_path"] = env_path - - monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) - - result = runner.invoke( - app, - ["eval", "run", "gsm8k-v1", "--sampling.temperature", "0.2"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured == { - "environment": "gsm8k-v1", - "passthrough_args": ["--sampling.temperature", "0.2"], - "skip_upload": False, - "env_path": None, - } - - -def test_eval_run_legacy_sampling_args_passthrough(monkeypatch): - captured = {} - - def fake_run_eval_passthrough(environment, passthrough_args, skip_upload, env_path): - captured["environment"] = environment - captured["passthrough_args"] = passthrough_args - - monkeypatch.setattr("prime_cli.commands.evals.run_eval_passthrough", fake_run_eval_passthrough) - - result = runner.invoke( - app, - [ - "eval", - "run", - "legacy-env", - "-s", - "--sampling-args", - '{"temperature":0.2}', - ], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - assert captured == { - "environment": "legacy-env", - "passthrough_args": [ - "-s", - "--sampling-args", - '{"temperature":0.2}', - ], - } - - -def test_eval_run_hosted_rejects_v0_only_flags(): - result = runner.invoke( - app, - ["eval", "run", "gsm8k", "--hosted", "--state-columns", "turn,timing"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 2 - - def test_eval_run_hosted_passes_env_path_to_resolver(monkeypatch): captured = {} @@ -1585,8 +1488,8 @@ def test_eval_logs_command_follows_incremental_output(monkeypatch): ) logs = iter( [ - "Line 1\nLine 2", - "Line 1\nLine 2\nLine 3", + "Line 1\nLine 2 [/yellow]", + "Line 1\nLine 2 [/yellow]\nLine 3", ] ) @@ -1612,6 +1515,8 @@ def test_eval_logs_command_follows_incremental_output(monkeypatch): assert "Line 2" in result.output assert "Line 3" in result.output assert result.output.count("Line 1") == 1 + assert "Line 2 [/yellow]" in result.output + assert "MarkupError" not in result.output assert "Status: COMPLETED" in result.output @@ -1656,123 +1561,3 @@ def test_eval_logs_command_emits_waiting_status_when_logs_are_unchanged(monkeypa assert result.output.count("Line 1") == 1 assert "Evaluation status: RUNNING (waiting for logs...)" in result.output assert "Status: COMPLETED" in result.output - - -V1_HOSTED_TOML = """\ -model = "openai/gpt-4.1-mini" -num_tasks = 7 -num_rollouts = 2 -max_concurrent = 16 - -[taskset] -id = "gsm8k-v1" -difficulty = "easy" - -[harness] -id = "default" - -[sampling] -temperature = 0.3 - -[retries.rollout] -max_retries = 2 - -[client.headers] -X-Custom = "yes" -""" - - -def test_eval_run_hosted_v1_config_sends_environments(monkeypatch, tmp_path): - captured = {} - - def fail_resolve(*args, **kwargs): - raise AssertionError("raw v1 hosted evals must not resolve a published environment") - - monkeypatch.setattr("prime_cli.commands.evals._resolve_hosted_environment", fail_resolve) - - def fake_create(config, environment_ids=None): - captured["payload"] = _build_hosted_evaluation_payload(config) - captured["environment_ids"] = environment_ids - return {"evaluation_id": "eval-123"} - - monkeypatch.setattr("prime_cli.commands.evals._create_hosted_evaluations", fake_create) - - config_path = tmp_path / "eval.toml" - config_path.write_text(V1_HOSTED_TOML) - result = runner.invoke( - app, - ["eval", str(config_path), "--hosted", "-n", "9"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 0, result.output - payload = captured["payload"] - assert "environment_ids" not in payload - assert payload["environments"] == [ - { - "taskset": {"id": "gsm8k-v1", "difficulty": "easy"}, - "harness": {"id": "default"}, - "retries": {"rollout": {"max_retries": 2}}, - "sampling": {"temperature": 0.3}, - } - ] - assert payload["eval_config"]["num_examples"] == 9 # CLI override wins over num_tasks - assert payload["eval_config"]["rollouts_per_example"] == 2 - assert payload["eval_config"]["max_concurrent"] == 16 - assert payload["eval_config"]["headers"] == ["X-Custom: yes"] - assert captured["environment_ids"] is None - assert "Hosted evaluation started" in result.output - - -def test_eval_run_hosted_v1_config_rejects_local_only_fields(monkeypatch, tmp_path): - config_path = tmp_path / "eval.toml" - config_path.write_text('output_dir = "outputs"\n\n[taskset]\nid = "gsm8k-v1"\n') - - result = runner.invoke( - app, - ["eval", "run", str(config_path), "--hosted"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 1 - assert "does not support" in result.output - assert "output_dir" in result.output - - -def test_eval_run_hosted_legacy_id_config_needs_published_env(monkeypatch, tmp_path): - config_path = tmp_path / "eval.toml" - config_path.write_text('id = "reverse-text"\nmodel = "openai/gpt-4.1-mini"\n') - - result = runner.invoke( - app, - ["eval", "run", str(config_path), "--hosted"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - - assert result.exit_code == 1 - assert "published environment" in result.output - - -def test_hosted_overrides_forward_client_base_url_and_api_key_var(): - """--client.base-url and --client.api-key-var on the hosted CLI must reach the - hosted payload, not be silently dropped after pydantic_cli parses them.""" - from prime_cli.commands.evals import _hosted_overrides_from_flags - - overrides = _hosted_overrides_from_flags( - ["--client.base-url", "https://api.openai.com/v1", "--client.api-key-var", "OPENAI_API_KEY"] - ) - assert overrides["api_base_url"] == "https://api.openai.com/v1" - assert overrides["api_key_var"] == "OPENAI_API_KEY" - - -def test_load_v1_hosted_target_defaults_num_examples_to_all_when_omitted(tmp_path): - """A v1 hosted TOML with [taskset] but no num_tasks means "all tasks"; - the platform spells that -1, not the hosted default of 5.""" - from prime_cli.commands.evals import _load_v1_hosted_target - - config = tmp_path / "eval.toml" - config.write_text('[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") - - target = _load_v1_hosted_target(config) - assert target is not None - assert target["num_examples"] == -1 diff --git a/packages/prime/tests/test_lab_view.py b/packages/prime/tests/test_lab_view.py index 437725671..6f000bc10 100644 --- a/packages/prime/tests/test_lab_view.py +++ b/packages/prime/tests/test_lab_view.py @@ -7918,22 +7918,3 @@ def _local_eval_item( "metadata": metadata, }, ) - - -def test_discover_local_eval_runs_finds_custom_output_dir(tmp_path: Path) -> None: - """Native v1 runs in a custom output_dir (no env--model in the path) must be - discovered by metadata, not skipped because the dir name lacks '--'.""" - run_dir = tmp_path / "outputs" / "my-custom-run" / "abc-123" - run_dir.mkdir(parents=True) - (run_dir / "metadata.json").write_text( - '{"env": "wiki-search", "model": "openai/gpt-4.1", "avg_reward": 0.8}', - encoding="utf-8", - ) - (run_dir / "results.jsonl").write_text('{"reward": 0.8}\n', encoding="utf-8") - - runs = discover_local_eval_runs(tmp_path) - - assert len(runs) == 1 - assert runs[0]["env_id"] == "wiki-search" - assert runs[0]["model"] == "openai/gpt-4.1" - assert runs[0]["run_id"] == "abc-123" diff --git a/packages/prime/tests/test_validate.py b/packages/prime/tests/test_validate.py deleted file mode 100644 index 19250eb63..000000000 --- a/packages/prime/tests/test_validate.py +++ /dev/null @@ -1,174 +0,0 @@ -"""Tests for `prime eval validate` — the wrapper around verifiers' model-free `validate`.""" - -import pytest -import typer -from prime_cli.main import app -from prime_cli.verifiers_bridge import ResolvedEnvironment, run_validate_passthrough -from prime_cli.verifiers_plugin import PrimeVerifiersPlugin -from typer.testing import CliRunner - -runner = CliRunner() - - -class DummyConfig: - api_key = "test-api-key" - inference_url = "https://api.pinference.ai/api/v1" - team_id = "team-abc" - - -class DummyPlugin: - eval_module = "verifiers.v1.cli.eval.main" - init_module = "verifiers.v1.cli.init" - validate_module = "verifiers.v1.cli.validate" - gepa_module = "verifiers.scripts.gepa" - - def build_module_command(self, module: str, args: list[str]) -> list[str]: - return [module, *args] - - -def _install_dummies(monkeypatch, captured: dict): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - - def fake_run(command, env=None): - captured.update(command=command, env=env) - - monkeypatch.setattr("prime_cli.verifiers_bridge._run_command", fake_run) - - -def test_validate_help_flags_use_backend_help(monkeypatch): - def fake_help() -> None: - print("BACKEND_HELP") - - monkeypatch.setattr("prime_cli.commands.evals.print_validate_help", fake_help) - for flag in ("-h", "--help"): - result = runner.invoke( - app, ["eval", "validate", flag], env={"PRIME_DISABLE_VERSION_CHECK": "1"} - ) - assert result.exit_code == 0, result.output - assert "BACKEND_HELP" in result.output - - -def test_validate_missing_environment_shows_help(): - # no_args_is_help: bare `prime eval validate` prints help and exits 2 - result = runner.invoke(app, ["eval", "validate"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}) - assert result.exit_code == 2, result.output - assert "Usage: prime eval validate" in result.output - - -def test_validate_rejects_leading_flag_as_environment(): - # with no declared typer options, the first unknown flag is captured as the - # positional `environment` and rejected with the "must be the first argument" guard - result = runner.invoke( - app, - ["eval", "validate", "--num-tasks", "5"], - env={"PRIME_DISABLE_VERSION_CHECK": "1"}, - ) - assert result.exit_code == 2, result.output - assert "must be the first argument" in result.output - - -def test_validate_requires_api_key(monkeypatch): - class NoKeyConfig: - api_key = "" - inference_url = "" - team_id = None - - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: NoKeyConfig()) - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - - with pytest.raises(typer.Exit) as exc_info: - run_validate_passthrough(environment="gsm8k-v1", passthrough_args=[]) - - assert exc_info.value.exit_code == 1 - - -def test_validate_environment_id_resolves_and_passes_bare_name(monkeypatch, tmp_path): - captured: dict = {} - _install_dummies(monkeypatch, captured) - prepared = {} - - monkeypatch.setattr( - "prime_cli.verifiers_bridge._prepare_v1_environment", - lambda env_name, env_dir: ( - prepared.update(env=env_name, env_dir=env_dir) - or ResolvedEnvironment(original=env_name, env_name=env_name, install_mode="local") - ), - ) - - run_validate_passthrough( - environment="gsm8k-v1", - passthrough_args=["--num-tasks", "5", "--env-dir-path", str(tmp_path / "envs")], - ) - - command = captured["command"] - assert command[0] == "verifiers.v1.cli.validate" - assert command[1] == "gsm8k-v1" # bare env name, not the path - assert "--num-tasks" in command and "5" in command - assert "--env-dir-path" not in command # stripped (prime-only) - assert prepared == {"env": "gsm8k-v1", "env_dir": str(tmp_path / "envs")} - assert captured["env"]["PRIME_API_KEY"] == "test-api-key" - assert captured["env"]["PRIME_INFERENCE_URL"] == DummyConfig.inference_url - assert captured["env"]["PRIME_TEAM_ID"] == "team-abc" - - -def test_validate_strips_at_prefix_for_config_target(monkeypatch, tmp_path): - captured: dict = {} - _install_dummies(monkeypatch, captured) - config_path = tmp_path / "validate.toml" - config_path.write_text('[taskset]\nid = "gsm8k-v1"\n', encoding="utf-8") - - run_validate_passthrough( - environment=f"@{config_path}", - passthrough_args=["--num-tasks", "5"], - ) - - command = captured["command"] - assert command[0] == "verifiers.v1.cli.validate" - # pydantic-config reads a root config file as two tokens: `@ path` - assert command[1:3] == ["@", str(config_path)] - assert "--num-tasks" in command - - -def test_validate_at_without_path_errors(monkeypatch): - monkeypatch.setattr( - "prime_cli.verifiers_bridge.load_verifiers_prime_plugin", lambda: DummyPlugin() - ) - monkeypatch.setattr("prime_cli.verifiers_bridge.Config", lambda: DummyConfig()) - - result = runner.invoke(app, ["eval", "validate", "@"], env={"PRIME_DISABLE_VERSION_CHECK": "1"}) - assert result.exit_code == 2, result.output - assert "must be followed by a config path" in result.output - - -def test_validate_module_uses_console_entrypoint_shim(monkeypatch): - monkeypatch.setattr("prime_cli.verifiers_plugin.resolve_workspace_python", lambda: "python") - plugin = PrimeVerifiersPlugin() - - command = plugin.build_module_command(plugin.validate_module, ["--help"]) - - assert command[:2] == ["python", "-c"] - assert "sys.argv[0] = 'validate'" in command[2] - assert "from verifiers.v1.cli.validate import main" in command[2] - assert command[-1] == "--help" - - -def test_sanitize_help_rewrites_validate_console_script(): - from prime_cli.verifiers_bridge import _sanitize_help_text - - # validate's prog is `validate` (not `main.py` like eval); both usage lines carry it. - raw = ( - "usage: validate [] [--runtime.type subprocess] [options] [@ file.toml]\n" - " runs each task's `validate` hook\n" - "usage: validate [-h] --taskset.id ID [OPTIONS]\n" - ) - help_text = _sanitize_help_text(raw, "verifiers.v1.cli.validate", "prime eval validate") - - assert help_text.count("Usage: prime eval validate") == 2 - assert "verifiers.v1.cli.validate" not in help_text - # the bare `usage: validate` lines are rewritten, not left behind - assert help_text.lower().count("usage: validate ") == 0 diff --git a/packages/prime/tests/test_verifiers_plugin_modules.py b/packages/prime/tests/test_verifiers_plugin_modules.py deleted file mode 100644 index 4e5657765..000000000 --- a/packages/prime/tests/test_verifiers_plugin_modules.py +++ /dev/null @@ -1,24 +0,0 @@ -"""The plugin's module paths must exist in the installed verifiers. - -Prime shells out to these modules by name; a rename on the verifiers side otherwise -surfaces only as a ModuleNotFoundError at `prime gepa run` / `prime eval` time. -""" - -import importlib.util - -import pytest -from prime_cli.verifiers_plugin import PrimeVerifiersPlugin - -pytest.importorskip("verifiers") - - -def test_plugin_modules_resolve_in_installed_verifiers(): - plugin = PrimeVerifiersPlugin() - modules = ( - plugin.eval_module, - plugin.init_module, - plugin.validate_module, - plugin.gepa_module, - ) - missing = [module for module in modules if importlib.util.find_spec(module) is None] - assert not missing, f"plugin points at modules verifiers no longer ships: {missing}"