From 9c0f5145c4c5b71fb2229d6cf328341088f899b8 Mon Sep 17 00:00:00 2001 From: William Benoit Date: Tue, 14 Apr 2026 11:45:07 -0500 Subject: [PATCH] Duplicate remote training logic in train project --- projects/export/pyproject.toml | 4 +- projects/export/uv.lock | 43 +---- projects/online/pyproject.toml | 2 +- projects/train/pyproject.toml | 4 +- projects/train/train/helm.py | 142 ++++++++++++++++ projects/train/train/remote.py | 295 +++++++++++++++++++++++++++++++++ projects/train/uv.lock | 86 +++++++--- pyproject.toml | 2 +- uv.lock | 71 +++++++- 9 files changed, 576 insertions(+), 73 deletions(-) create mode 100644 projects/train/train/helm.py create mode 100644 projects/train/train/remote.py diff --git a/projects/export/pyproject.toml b/projects/export/pyproject.toml index 7984579c..408c4266 100644 --- a/projects/export/pyproject.toml +++ b/projects/export/pyproject.toml @@ -13,8 +13,8 @@ dependencies = [ "aframe", "utils", "jsonargparse>=4.27.1,<5", - "nvidia-cudnn-cu11", - "tensorrt", + "nvidia-cudnn-cu12", + "tensorrt>=10.0", "urllib3>=2", ] diff --git a/projects/export/uv.lock b/projects/export/uv.lock index f341c064..d408303d 100644 --- a/projects/export/uv.lock +++ b/projects/export/uv.lock @@ -340,7 +340,7 @@ dependencies = [ { name = "jsonargparse" }, { name = "ml4gw" }, { name = "ml4gw-hermes", extra = ["torch"] }, - { name = "nvidia-cudnn-cu11" }, + { name = "nvidia-cudnn-cu12" }, { name = "tensorrt" }, { name = "urllib3" }, { name = "utils" }, @@ -359,8 +359,8 @@ requires-dist = [ { name = "jsonargparse", specifier = ">=4.27.1,<5" }, { name = "ml4gw", specifier = ">=0.7.7" }, { name = "ml4gw-hermes", extras = ["torch"], git = "https://github.com/ML4GW/hermes?branch=dev" }, - { name = "nvidia-cudnn-cu11" }, - { name = "tensorrt" }, + { name = "nvidia-cudnn-cu12" }, + { name = "tensorrt", specifier = ">=10.0" }, { name = "urllib3", specifier = ">=2" }, { name = "utils", editable = "../../libs/utils" }, ] @@ -887,23 +887,14 @@ wheels = [ { 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" }, ] -[[package]] -name = "nvidia-cublas-cu11" -version = "11.11.3.6" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/be/c222e33e60d28ecd496a46fc4d78ccae0ee28e1fd7dc705b6288b4cad27e/nvidia_cublas_cu11-11.11.3.6-py3-none-manylinux1_x86_64.whl", hash = "sha256:39fb40e8f486dd8a2ddb8fdeefe1d5b28f5b99df01c87ab3676f057a74a5a6f3", size = 417870452, upload-time = "2022-10-18T21:17:48.638Z" }, - { url = "https://files.pythonhosted.org/packages/96/df/c5ac9ac5096355c47c606e613ecc7aa50fbccf5e0145df857d11da6464b1/nvidia_cublas_cu11-11.11.3.6-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5ccae9e069a2c6be9af9cb5a0b0c6928c19c7915e390d15f598a1eead2a01a7a", size = 291428448, upload-time = "2024-08-16T23:59:46.358Z" }, - { url = "https://files.pythonhosted.org/packages/ea/2e/9d99c60771d275ecf6c914a612e9a577f740a615bc826bec132368e1d3ae/nvidia_cublas_cu11-11.11.3.6-py3-none-manylinux2014_x86_64.whl", hash = "sha256:60252822adea5d0b10cd990a7dc7bedf7435f30ae40083c7a624a85a43225abc", size = 417870460, upload-time = "2024-08-17T00:00:26.889Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1d/7a78cd36fd5e3da4021b3ac2c2c8b2651dd72345b7c3ecc0d3e051884f50/nvidia_cublas_cu11-11.11.3.6-py3-none-win_amd64.whl", hash = "sha256:6ab12b1302bef8ac1ff4414edd1c059e57f4833abef9151683fb8f4de25900be", size = 427234740, upload-time = "2022-10-18T21:21:50.058Z" }, -] - [[package]] name = "nvidia-cublas-cu12" version = "12.4.5.8" source = { registry = "https://pypi.org/simple" } wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/7f/7fbae15a3982dc9595e49ce0f19332423b260045d0a6afe93cdbe2f1f624/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3", size = 363333771, upload-time = "2024-06-18T19:28:09.881Z" }, { url = "https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b", size = 363438805, upload-time = "2024-04-03T20:57:06.025Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2a/4f27ca96232e8b5269074a72e03b4e0d43aa68c9b965058b1684d07c6ff8/nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc", size = 396895858, upload-time = "2024-04-03T21:03:31.996Z" }, ] [[package]] @@ -914,17 +905,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb", size = 13813957, upload-time = "2024-04-03T20:55:01.564Z" }, ] -[[package]] -name = "nvidia-cuda-nvrtc-cu11" -version = "11.8.89" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/08/a9833e4e9f9165bedb7f36033b47aa399b053b9cb2eaf7b84d1e28705cf7/nvidia_cuda_nvrtc_cu11-11.8.89-py3-none-manylinux1_x86_64.whl", hash = "sha256:1f27d67b0f72902e9065ae568b4f6268dfe49ba3ed269c9a3da99bb86d1d2008", size = 23173264, upload-time = "2022-10-03T21:47:00.705Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ad/58a9f86b0280190582691b1141ac3678c08f698d3d6161eed5cbe4e43b46/nvidia_cuda_nvrtc_cu11-11.8.89-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8ab17ed51e7c4928f7170a0551e3e3b42f89d973bd267ced9688c238b3e10aef", size = 22671777, upload-time = "2024-08-16T23:57:58.688Z" }, - { url = "https://files.pythonhosted.org/packages/60/44/202e027c224c26e15a53f01c5c7604c7f6b4fd368882d3164ea08fead207/nvidia_cuda_nvrtc_cu11-11.8.89-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a8d02f3cba345be56b1ffc3e74d8f61f02bb758dd31b0f20e12277a5a244f756", size = 23173745, upload-time = "2024-08-16T23:58:16.539Z" }, - { url = "https://files.pythonhosted.org/packages/c9/19/17745076214b0cc985cfdbabe2b3108f1237704985dab5b748e48432aca1/nvidia_cuda_nvrtc_cu11-11.8.89-py3-none-win_amd64.whl", hash = "sha256:e18a23a8f4064664a6f1c4a64f38c581cbebfb5935280e94a4943ea8ae3791b1", size = 19034935, upload-time = "2022-10-03T23:39:03.211Z" }, -] - [[package]] name = "nvidia-cuda-nvrtc-cu12" version = "12.4.127" @@ -941,18 +921,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ea/27/1795d86fe88ef397885f2e580ac37628ed058a92ed2c39dc8eac3adf0619/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5", size = 883737, upload-time = "2024-04-03T20:54:51.355Z" }, ] -[[package]] -name = "nvidia-cudnn-cu11" -version = "8.9.6.50" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu11" }, - { name = "nvidia-cuda-nvrtc-cu11" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/2d/3f083fcff1c302119f48e7b30a5f7b23db793f262f900943a9eb456b9e4d/nvidia_cudnn_cu11-8.9.6.50-py3-none-manylinux1_x86_64.whl", hash = "sha256:319a8f7ca3d65139f1b69998595c7076ae0e4271a325e5dfde50a3ca31f55584", size = 699874407, upload-time = "2023-11-01T23:40:02.18Z" }, -] - [[package]] name = "nvidia-cudnn-cu12" version = "9.1.0.70" @@ -962,6 +930,7 @@ dependencies = [ ] wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741, upload-time = "2024-04-22T15:24:15.253Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d0/f90ee6956a628f9f04bf467932c0a25e5a7e706a684b896593c06c82f460/nvidia_cudnn_cu12-9.1.0.70-py3-none-win_amd64.whl", hash = "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a", size = 679925892, upload-time = "2024-04-22T15:24:53.333Z" }, ] [[package]] diff --git a/projects/online/pyproject.toml b/projects/online/pyproject.toml index 2f06da01..720b2f66 100644 --- a/projects/online/pyproject.toml +++ b/projects/online/pyproject.toml @@ -45,7 +45,7 @@ dev = [ [[tool.uv.index]] name = "torch" -url = "https://download.pytorch.org/whl/cu118" +url = "https://download.pytorch.org/whl/cu124" explicit = true [tool.uv.sources] diff --git a/projects/train/pyproject.toml b/projects/train/pyproject.toml index 2e9a24ee..133569ab 100644 --- a/projects/train/pyproject.toml +++ b/projects/train/pyproject.toml @@ -31,10 +31,12 @@ dependencies = [ "filelock>=3.13.1,<4", "s3fs>=2024,<2025", "lightray>=0.2.3", + "kr8s>=0.20.0", ] [project.scripts] train = "train.cli:main" +train-remote = "train.remote:main" [dependency-groups] dev = [ @@ -46,7 +48,7 @@ dev = [ [[tool.uv.index]] name = "torch" -url = "https://download.pytorch.org/whl/cu118" +url = "https://download.pytorch.org/whl/cu124" explicit = true [tool.uv.sources] diff --git a/projects/train/train/helm.py b/projects/train/train/helm.py new file mode 100644 index 00000000..d24866e2 --- /dev/null +++ b/projects/train/train/helm.py @@ -0,0 +1,142 @@ +""" +Tools for deploying helm charts +""" + +import logging +import subprocess +import time + +# httpx-ws 0.9.0 references anyio.AsyncContextManagerMixin +# which was removed in anyio 4.0. +# Remove once httpx-ws releases a fix. +import anyio + +if not hasattr(anyio, "AsyncContextManagerMixin"): + anyio.AsyncContextManagerMixin = object + +import kr8s + +CHART_REPO = "https://github.com/EthanMarx/lightray/releases/download/" + + +def authenticate(): + result = subprocess.run( + ["kubectl", "cluster-info"], + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + ) + if result.returncode != 0: + logging.warning( + "kubectl cluster-info failed (returncode %d): %s", + result.returncode, + result.stderr.decode().strip(), + ) + + +# used to monkey patch kr8s api refresh method; +# see https://github.com/kr8s-org/kr8s/issues/214 +async def auth(self): + """ + Replacement reauthenticate method that + uses kubectl to refresh the OIDC token + """ + authenticate() + await self._load_kubeconfig() + + +def setup_kr8s_auth(): + """ + Return a kr8s API instance with its reauthenticate method patched + to use kubectl for OIDC token refresh. + + Call this before any kr8s operations that require cluster access. + """ + api = kr8s.api() + api.auth.reauthenticate = auth.__get__(api.auth, type(api.auth)) + return api + + +class HelmChart: + def __init__(self, chart_url: str, release: str): + self.chart_url = chart_url + self.release = release + base_cmd = ["helm", "install", self.release, self.chart_url] + + self.base_cmd = base_cmd + self.api = setup_kr8s_auth() + + def install(self): + logging.info(f"Installing chart from {self.chart_url}") + try: + subprocess.run(self.base_cmd, check=True) + except subprocess.CalledProcessError as e: + logging.error(f"Error installing helm chart: {e}") + raise + + def build_command(self, values: dict[str, str]) -> list[str]: + for k, v in values.items(): + self.base_cmd += ["--set", f"{k}={v}"] + + def uninstall(self): + subprocess.run(["helm", "uninstall", self.release], check=True) + + def wait(self): + raise NotImplementedError + + def __enter__(self): + self.install() + self.wait() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.uninstall() + super().__exit__(exc_type, exc_value, traceback) + + +class RayCluster(HelmChart): + def __init__( + self, + release: str, + chart_path: str | None = None, + chart_version: str = "0.1.3", + ): + # if no chart path is provided, use the chart + # in the github repo + if chart_path is None: + chart_path = f"{CHART_REPO}/ray-cluster-{chart_version}" + chart_path += f"/ray-cluster-{chart_version}.tgz" + super().__init__(chart_path, release) + + def get_ip(self): + services = kr8s.get("service") + services = [s for s in services if s.name.startswith(self.release)] + service = [s for s in services if s.spec["type"] == "LoadBalancer"][0] + service.refresh() + return service.status.loadBalancer.ingress[0].ip + + def get_pods(self): + pods = kr8s.get("pod") + # filter for pods related to this release + # and that aren't terminating from a previous run + pods = [ + p + for p in pods + if p.name.startswith(self.release) + and p.status.phase in ["Pending", "Running"] + ] + + head = [p for p in pods if "head" in p.name][0] + workers = [p for p in pods if "worker" in p.name] + return head, workers + + def wait(self): + # get pods related to this release + head, workers = self.get_pods() + + # wait for pods to be ready; + # can subclass to define "readiness" + ready = False + while not ready: + ready = any(p.ready() for p in workers) + ready = ready and head.ready() + time.sleep(2) diff --git a/projects/train/train/remote.py b/projects/train/train/remote.py new file mode 100644 index 00000000..125336c3 --- /dev/null +++ b/projects/train/train/remote.py @@ -0,0 +1,295 @@ +import base64 +import logging +import os +import time +from dataclasses import dataclass, field +from pathlib import Path + +import jsonargparse +from kr8s.objects import Pod, Secret +from utils.logging import configure_logging + +from train.helm import authenticate, setup_kr8s_auth + +# Maps external Nautilus S3 URLs to the internal cluster equivalents. +_NAUTILUS_INTERNAL_URLS = { + "https://s3-west.nrp-nautilus.io": "https://s3-west.nrp-nautilus.io", + "https://s3-central.nrp-nautilus.io": "http://rook-ceph-rgw-centrals3.rook-central", # noqa: E501 + "https://s3-east.nrp-nautilus.io": "http://rook-ceph-rgw-easts3.rook-east", +} + + +@dataclass +class RemoteTrainer: + """ + Manages a remote training job on a Kubernetes cluster. + """ + + remote_image: str = "ghcr.io/ml4gw/aframe/train:main" + request_gpus: int = 8 + cpus_per_gpu: int = 12 + memory_per_cpu: float = 4.0 + base_memory: int = 32 + min_gpu_memory: int = 15000 + aws_endpoint_url: str = field( + default_factory=lambda: os.getenv("AWS_ENDPOINT_URL", "") + ) + aws_access_key_id: str = field( + default_factory=lambda: os.getenv("AWS_ACCESS_KEY_ID", "") + ) + aws_secret_access_key: str = field( + default_factory=lambda: os.getenv("AWS_SECRET_ACCESS_KEY", "") + ) + wandb_api_key: str = field( + default_factory=lambda: os.getenv("WANDB_API_KEY", "") + ) + use_git_sync: bool = False + git_url: str = "git@github.com:ML4GW/aframe.git" + git_ref: str = "main" + namespace: str = "bbhnet" + pod_creation_timeout: int = 7200 + + @property + def internal_endpoint_url(self) -> str: + """ + Remap external Nautilus URLs to their internal cluster equivalents. + """ + return _NAUTILUS_INTERNAL_URLS.get( + self.aws_endpoint_url, self.aws_endpoint_url + ) + + @property + def num_cpus(self) -> int: + return self.request_gpus * self.cpus_per_gpu + + @property + def cpu_memory(self) -> str: + memory = self.memory_per_cpu * self.num_cpus + self.base_memory + return f"{memory}G" + + def git_secret(self) -> Secret: + ssh_key_path = Path.home() / ".ssh" / "id_rsa" + with open(ssh_key_path) as f: + key = f.read() + encoded = base64.b64encode(key.encode("ascii")).decode("ascii") + spec = { + "apiVersion": "v1", + "kind": "Secret", + "metadata": {"name": "git-creds", "namespace": self.namespace}, + "type": "Opaque", + "data": {"ssh": encoded}, + } + return Secret(resource=spec) + + def pod_spec(self, args: list[str]) -> dict: + spec = { + "affinity": { + "nodeAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": { + "nodeSelectorTerms": [ + { + "matchExpressions": [ + { + "key": "nvidia.com/gpu.memory", + "operator": "Gt", + "values": [f"{self.min_gpu_memory}"], + } + ] + } + ] + } + } + }, + "restartPolicy": "Never", + "containers": [ + { + "name": "train", + "image": self.remote_image, + "imagePullPolicy": "Always", + "command": ["python", "-m", "train"], + "args": args, + "volumeMounts": [ + {"mountPath": "/dev/shm", "name": "dshm"}, + ], + "resources": { + "limits": { + "memory": self.cpu_memory, + "cpu": f"{self.num_cpus}", + "nvidia.com/gpu": f"{self.request_gpus}", + }, + "requests": { + "memory": self.cpu_memory, + "cpu": f"{self.num_cpus}", + "nvidia.com/gpu": f"{self.request_gpus}", + }, + }, + "envFrom": [{"secretRef": {"name": "s3-credentials"}}], + "env": [ + { + "name": "AWS_ENDPOINT_URL", + "value": self.internal_endpoint_url, + }, + { + "name": "WANDB_API_KEY", + "value": self.wandb_api_key, + }, + ], + } + ], + "volumes": [ + { + "name": "dshm", + "emptyDir": {"sizeLimit": "256Gi", "medium": "Memory"}, + }, + ], + } + + if self.use_git_sync: + spec["initContainers"] = [ + { + "name": "git-sync", + "image": "registry.k8s.io/git-sync/git-sync:v4.2.1", + "env": [ + {"name": "GITSYNC_REPO", "value": self.git_url}, + {"name": "GITSYNC_REF", "value": self.git_ref}, + {"name": "GITSYNC_ROOT", "value": "/opt"}, + {"name": "GITSYNC_LINK", "value": "aframe"}, + {"name": "GITSYNC_ONE_TIME", "value": "true"}, + {"name": "GITSYNC_SSH_KNOWN_HOSTS", "value": "false"}, + {"name": "GITSYNC_SUBMODULES", "value": "recursive"}, + {"name": "GITSYNC_ADD_USER", "value": "true"}, + {"name": "GITSYNC_SYNC_TIMEOUT", "value": "360s"}, + ], + "volumeMounts": [ + {"name": "aframe", "mountPath": "/opt"}, + { + "name": "git-creds", + "mountPath": "/etc/git-secret", + "readOnly": True, + }, + ], + "securityContext": {"runAsUser": 65533}, + } + ] + spec["containers"][0]["volumeMounts"].append( + {"mountPath": "/opt", "name": "aframe"} + ) + spec["volumes"] += [ + {"name": "aframe", "emptyDir": {}}, + {"name": "git-creds", "secret": {"secretName": "git-creds"}}, + ] + + return spec + + def wait_for_completion(self, pod: Pod) -> str: + """ + Poll the pod until it terminates. + """ + start = time.monotonic() + while True: + pod.refresh() + phase = pod.status.phase + if phase in ("Succeeded", "Failed"): + return phase + elapsed = time.monotonic() - start + if elapsed > self.pod_creation_timeout and phase == "Pending": + raise TimeoutError( + f"Pod still Pending after {self.pod_creation_timeout}s" + ) + time.sleep(10) + + def run(self, args: list[str]) -> None: + """ + Launch a training pod on Kubernetes, stream its logs, and + wait for completion. Cleans up secrets and the pod on exit. + + Args: + args: Arguments forwarded verbatim to `python -m train` + inside the pod (e.g. ["fit", "--config", "..."]). + """ + authenticate() + setup_kr8s_auth() + + s3_secret = Secret( + resource={ + "apiVersion": "v1", + "kind": "Secret", + "metadata": { + "name": "s3-credentials", + "namespace": self.namespace, + }, + "type": "Opaque", + "stringData": { + "AWS_ACCESS_KEY_ID": self.aws_access_key_id, + "AWS_SECRET_ACCESS_KEY": self.aws_secret_access_key, + }, + } + ) + git_secret = self.git_secret() if self.use_git_sync else None + + if not s3_secret.exists(): + s3_secret.create() + if git_secret is not None and not git_secret.exists(): + git_secret.create() + + pod_manifest = { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "aframe-train", + "namespace": self.namespace, + }, + "spec": self.pod_spec(args), + } + pod = Pod(resource=pod_manifest) + + try: + pod.create() + logging.info( + f"Created pod aframe-train in namespace {self.namespace}" + ) + for line in pod.logs(follow=True): + logging.info(line) + phase = self.wait_for_completion(pod) + if phase != "Succeeded": + raise RuntimeError( + f"Training pod terminated with phase '{phase}'" + ) + logging.info("Training completed successfully") + finally: + pod.delete() + s3_secret.delete() + if git_secret is not None: + git_secret.delete() + + +def build_parser(): + parser = jsonargparse.ArgumentParser() + parser.add_argument("--config", action=jsonargparse.ActionConfigFile) + parser.add_argument("--logfile", type=str, default=None) + parser.add_argument("--verbose", type=bool, default=False) + parser.add_class_arguments(RemoteTrainer) + parser.add_argument( + "--train_args", + nargs="*", + default=[], + help="Arguments forwarded verbatim to `python -m train` in the pod " + "(e.g. fit --config config.yaml --data.sample_rate 2048).", + ) + return parser + + +def main(args=None): + parser = build_parser() + cfg = parser.parse_args(args) + + if cfg.logfile is not None: + Path(cfg.logfile).parent.mkdir(parents=True, exist_ok=True) + configure_logging(cfg.logfile, cfg.verbose) + + cfg = parser.instantiate_classes(cfg) + cfg.trainer.run(cfg.train_args) + + +if __name__ == "__main__": + main() diff --git a/projects/train/uv.lock b/projects/train/uv.lock index fce0f819..09499776 100644 --- a/projects/train/uv.lock +++ b/projects/train/uv.lock @@ -37,7 +37,7 @@ requires-dist = [ { name = "boto3", specifier = ">=1.34.4,<2" }, { name = "cloudpathlib", specifier = ">=0.18.1,<0.19" }, { name = "jsonargparse", specifier = ">=4.27.1,<5" }, - { name = "kr8s", specifier = ">=0.10.0,<0.11" }, + { name = "kr8s", specifier = ">=0.20.0" }, { name = "law", specifier = ">=0.1.20" }, { name = "luigi", specifier = "~=3.0" }, { name = "ml4gw-hermes", git = "https://github.com/ML4GW/hermes?branch=dev" }, @@ -206,16 +206,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d [[package]] name = "anyio" -version = "4.8.0" +version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, - { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126, upload-time = "2025-01-05T13:13:11.095Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041, upload-time = "2025-01-05T13:13:07.985Z" }, + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, ] [[package]] @@ -925,6 +924,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/ef/2196b9bf88ffa1bde45853c72df021fbd07a8fa91a0f59a22d14a050dc04/emcee-3.1.6-py2.py3-none-any.whl", hash = "sha256:f2d63752023bdccf744461450e512a5b417ae7d28f18e12acd76a33de87580cb", size = 47351, upload-time = "2024-04-19T10:03:17.522Z" }, ] +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + [[package]] name = "executing" version = "2.2.0" @@ -1242,6 +1253,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[[package]] +name = "httpx-ws" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpcore" }, + { name = "httpx" }, + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/cd/ca91a07ae446451f7476bf3fcc909e98cb942ff032ebfda0e3fe449aca7b/httpx_ws-0.9.0.tar.gz", hash = "sha256:797373326f70eec1ae96f6e43ae9f12002fd7d73aee139a4985eaab964338a08", size = 107105, upload-time = "2026-03-28T14:11:10.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/f8/a6bc80313a9e93c888fa10534dfce2ad76ff86911b6f485777ce6de6a073/httpx_ws-0.9.0-py3-none-any.whl", hash = "sha256:71640d2fb1bf9a225775015b33cd755cfd4c5f7e21c885192fe3adc4c387b248", size = 15759, upload-time = "2026-03-28T14:11:11.887Z" }, +] + [[package]] name = "idna" version = "3.10" @@ -1767,19 +1793,24 @@ wheels = [ [[package]] name = "kr8s" -version = "0.10.0" +version = "0.20.15" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, { name = "anyio" }, + { name = "cachetools" }, + { name = "cryptography" }, + { name = "exceptiongroup", marker = "python_full_version < '3.12'" }, { name = "httpx" }, + { name = "httpx-ws" }, + { name = "packaging" }, { name = "python-box" }, { name = "python-jsonpath" }, { name = "pyyaml" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/0a/db52898da5e1ca08e7e6e7b4c5f50edb4098400af903ca2bcc6161b4338d/kr8s-0.10.0.tar.gz", hash = "sha256:7963f52d24e567e6a2cb29adcaa8479daa5d47491d604036e0b169f5eac98942", size = 2811130, upload-time = "2023-11-06T16:09:09.069Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/55/ca9ff53d97413a0dca36c30da80750415350876aa23ea8a762a0b06c6d1f/kr8s-0.20.15.tar.gz", hash = "sha256:484d5206bbebd48f8cc00dd3ed749d4419294d2f08cd50c6232114cf62ed6d3a", size = 2839774, upload-time = "2026-01-16T15:23:42.645Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/ff/68600c19eaa59a4c7532dcdcf95bf151063d63bb359ce0611e2f666d09d5/kr8s-0.10.0-py3-none-any.whl", hash = "sha256:a558e6250b371a1210f62c9a4b72ee5cb59152550e405b6d1fe29a2767a3dfa8", size = 44656, upload-time = "2023-11-06T16:09:07.062Z" }, + { url = "https://files.pythonhosted.org/packages/59/08/4247abe88116c1e59dd9b62992d8a69b7178f4046c85cca03eda7e3d87e3/kr8s-0.20.15-py3-none-any.whl", hash = "sha256:eacc6eb72b6354d932a1e22c0cb698c88adbd815c36164c24c2232a69dfabe40", size = 87670, upload-time = "2026-01-16T15:23:40.593Z" }, ] [[package]] @@ -2399,7 +2430,7 @@ name = "nvidia-cudnn-cu12" version = "9.1.0.70" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741, upload-time = "2024-04-22T15:24:15.253Z" }, @@ -2410,7 +2441,7 @@ name = "nvidia-cufft-cu12" version = "11.2.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/27/94/3266821f65b92b3138631e9c8e7fe1fb513804ac934485a8d05776e1dd43/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9", size = 211459117, upload-time = "2024-04-03T20:57:40.402Z" }, @@ -2429,9 +2460,9 @@ name = "nvidia-cusolver-cu12" version = "11.6.1.9" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/3a/e1/5b9089a4b2a4790dfdea8b3a006052cfecff58139d5a4e34cb1a51df8d6f/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260", size = 127936057, upload-time = "2024-04-03T20:58:28.735Z" }, @@ -2442,7 +2473,7 @@ name = "nvidia-cusparse-cu12" version = "12.3.1.170" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/db/f7/97a9ea26ed4bbbfc2d470994b8b4f338ef663be97b8f677519ac195e113d/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1", size = 207454763, upload-time = "2024-04-03T20:58:59.995Z" }, @@ -3809,15 +3840,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, ] -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - [[package]] name = "soupsieve" version = "2.6" @@ -4044,6 +4066,7 @@ dependencies = [ { name = "filelock" }, { name = "fsspec", extra = ["s3"] }, { name = "jsonargparse", extra = ["signatures"] }, + { name = "kr8s" }, { name = "ledger" }, { name = "lightning" }, { name = "lightray" }, @@ -4074,6 +4097,7 @@ requires-dist = [ { name = "filelock", specifier = ">=3.13.1,<4" }, { name = "fsspec", extras = ["s3"], specifier = ">=2024,<2025" }, { name = "jsonargparse", extras = ["signatures"], specifier = "~=4.29" }, + { name = "kr8s", specifier = ">=0.20.0" }, { name = "ledger", editable = "../../libs/ledger" }, { name = "lightning", specifier = ">=2.2.1" }, { name = "lightray", specifier = ">=0.2.3" }, @@ -4108,7 +4132,7 @@ name = "triton" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "filelock", marker = "python_full_version < '3.13' and sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/86/17/d9a5cf4fcf46291856d1e90762e36cbabd2a56c7265da0d1d9508c8e3943/triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f34f6e7885d1bf0eaaf7ba875a5f0ce6f3c13ba98f9503651c1e6dc6757ed5c", size = 209506424, upload-time = "2024-10-14T16:05:42.337Z" }, @@ -4373,6 +4397,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, ] +[[package]] +name = "wsproto" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425, upload-time = "2022-08-23T19:58:21.447Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226, upload-time = "2022-08-23T19:58:19.96Z" }, +] + [[package]] name = "xyzservices" version = "2025.1.0" diff --git a/pyproject.toml b/pyproject.toml index d6cc847c..5abc9c5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "utils", "ml4gw-hermes", "law>=0.1.20", - "kr8s>=0.10.0,<0.11", + "kr8s>=0.20.0", "pykube-ng[oidc]>=23.6.0,<24", "spython>=0.3", "boto3>=1.34.4,<2", diff --git a/uv.lock b/uv.lock index 4b824dff..dd41a31b 100644 --- a/uv.lock +++ b/uv.lock @@ -45,7 +45,7 @@ requires-dist = [ { name = "boto3", specifier = ">=1.34.4,<2" }, { name = "cloudpathlib", specifier = ">=0.18.1,<0.19" }, { name = "jsonargparse", specifier = ">=4.27.1,<5" }, - { name = "kr8s", specifier = ">=0.10.0,<0.11" }, + { name = "kr8s", specifier = ">=0.20.0" }, { name = "law", specifier = ">=0.1.20" }, { name = "luigi", specifier = "~=3.0" }, { name = "ml4gw-hermes", git = "https://github.com/ML4GW/hermes?branch=dev" }, @@ -457,6 +457,15 @@ filecache = [ { name = "filelock" }, ] +[[package]] +name = "cachetools" +version = "7.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/dd/57fe3fdb6e65b25a5987fd2cdc7e22db0aef508b91634d2e57d22928d41b/cachetools-7.0.5.tar.gz", hash = "sha256:0cd042c24377200c1dcd225f8b7b12b0ca53cc2c961b43757e774ebe190fd990", size = 37367, upload-time = "2026-03-09T20:51:29.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl", hash = "sha256:46bc8ebefbe485407621d0a4264b23c080cedd913921bad7ac3ed2f26c183114", size = 13918, upload-time = "2026-03-09T20:51:27.33Z" }, +] + [[package]] name = "certifi" version = "2025.1.31" @@ -688,18 +697,24 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989, upload-time = "2024-10-18T15:58:32.918Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303, upload-time = "2024-10-18T15:57:36.753Z" }, { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905, upload-time = "2024-10-18T15:57:39.166Z" }, { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271, upload-time = "2024-10-18T15:57:41.227Z" }, { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606, upload-time = "2024-10-18T15:57:42.903Z" }, { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484, upload-time = "2024-10-18T15:57:45.434Z" }, { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131, upload-time = "2024-10-18T15:57:47.267Z" }, { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647, upload-time = "2024-10-18T15:57:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873, upload-time = "2024-10-18T15:57:51.822Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039, upload-time = "2024-10-18T15:57:54.426Z" }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984, upload-time = "2024-10-18T15:57:56.174Z" }, { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968, upload-time = "2024-10-18T15:57:58.206Z" }, { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754, upload-time = "2024-10-18T15:58:00.683Z" }, { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458, upload-time = "2024-10-18T15:58:02.225Z" }, { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220, upload-time = "2024-10-18T15:58:04.331Z" }, { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898, upload-time = "2024-10-18T15:58:06.113Z" }, { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592, upload-time = "2024-10-18T15:58:08.673Z" }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145, upload-time = "2024-10-18T15:58:10.264Z" }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026, upload-time = "2024-10-18T15:58:11.916Z" }, ] [[package]] @@ -806,6 +821,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f5/64/82570019b199a85b1d9559e75f448272fc6a79201d8692a1357f3f803837/ensureconda-1.6.0-py3-none-any.whl", hash = "sha256:df518b64b08640a1e5e37b1c80d90810a8f5ad0a1b9938aaa740653bb66ef538", size = 12077, upload-time = "2025-10-06T22:22:26.165Z" }, ] +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + [[package]] name = "executing" version = "2.2.0" @@ -1027,6 +1054,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[[package]] +name = "httpx-ws" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpcore" }, + { name = "httpx" }, + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/cd/ca91a07ae446451f7476bf3fcc909e98cb942ff032ebfda0e3fe449aca7b/httpx_ws-0.9.0.tar.gz", hash = "sha256:797373326f70eec1ae96f6e43ae9f12002fd7d73aee139a4985eaab964338a08", size = 107105, upload-time = "2026-03-28T14:11:10.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/f8/a6bc80313a9e93c888fa10534dfce2ad76ff86911b6f485777ce6de6a073/httpx_ws-0.9.0-py3-none-any.whl", hash = "sha256:71640d2fb1bf9a225775015b33cd755cfd4c5f7e21c885192fe3adc4c387b248", size = 15759, upload-time = "2026-03-28T14:11:11.887Z" }, +] + [[package]] name = "idna" version = "3.10" @@ -1050,7 +1092,7 @@ name = "importlib-metadata" version = "8.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/08/c1395a292bb23fd03bdf572a1357c5a733d3eecbab877641ceacab23db6e/importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580", size = 55767, upload-time = "2025-01-20T22:21:30.429Z" } wheels = [ @@ -1514,19 +1556,24 @@ wheels = [ [[package]] name = "kr8s" -version = "0.10.0" +version = "0.20.15" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, { name = "anyio" }, + { name = "cachetools" }, + { name = "cryptography" }, + { name = "exceptiongroup", marker = "python_full_version < '3.12'" }, { name = "httpx" }, + { name = "httpx-ws" }, + { name = "packaging" }, { name = "python-box" }, { name = "python-jsonpath" }, { name = "pyyaml" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/0a/db52898da5e1ca08e7e6e7b4c5f50edb4098400af903ca2bcc6161b4338d/kr8s-0.10.0.tar.gz", hash = "sha256:7963f52d24e567e6a2cb29adcaa8479daa5d47491d604036e0b169f5eac98942", size = 2811130, upload-time = "2023-11-06T16:09:09.069Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/55/ca9ff53d97413a0dca36c30da80750415350876aa23ea8a762a0b06c6d1f/kr8s-0.20.15.tar.gz", hash = "sha256:484d5206bbebd48f8cc00dd3ed749d4419294d2f08cd50c6232114cf62ed6d3a", size = 2839774, upload-time = "2026-01-16T15:23:42.645Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/ff/68600c19eaa59a4c7532dcdcf95bf151063d63bb359ce0611e2f666d09d5/kr8s-0.10.0-py3-none-any.whl", hash = "sha256:a558e6250b371a1210f62c9a4b72ee5cb59152550e405b6d1fe29a2767a3dfa8", size = 44656, upload-time = "2023-11-06T16:09:07.062Z" }, + { url = "https://files.pythonhosted.org/packages/59/08/4247abe88116c1e59dd9b62992d8a69b7178f4046c85cca03eda7e3d87e3/kr8s-0.20.15-py3-none-any.whl", hash = "sha256:eacc6eb72b6354d932a1e22c0cb698c88adbd815c36164c24c2232a69dfabe40", size = 87670, upload-time = "2026-01-16T15:23:40.593Z" }, ] [[package]] @@ -3560,6 +3607,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, ] +[[package]] +name = "wsproto" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425, upload-time = "2022-08-23T19:58:21.447Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226, upload-time = "2022-08-23T19:58:19.96Z" }, +] + [[package]] name = "xattr" version = "1.3.0"