Skip to content

Commit 20304af

Browse files
authored
fix: use volume version metadata when updating volumes (#279)
* encode volume content version in source prefix * use version from metadata * lint * format
1 parent d05090c commit 20304af

3 files changed

Lines changed: 20 additions & 14 deletions

File tree

src/together/lib/cli/api/beta/jig/_config.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
import json
88
import typing
9-
from typing import TYPE_CHECKING, Any, Union, Optional
9+
from typing import TYPE_CHECKING, Any, Union, Optional, cast
1010
from pathlib import Path
1111
from dataclasses import field, asdict, dataclass, is_dataclass
1212

@@ -60,6 +60,7 @@ class VolumeMount:
6060

6161
name: str
6262
mount_path: str
63+
version: Optional[int] = None
6364

6465
@classmethod
6566
def from_dict(cls, data: dict[str, Any]) -> VolumeMount:
@@ -84,7 +85,7 @@ class DeployConfig:
8485
port: int = 8000
8586
environment_variables: dict[str, str] = field(default_factory=dict[str, str])
8687
command: Optional[list[str]] = None
87-
autoscaling: dict[str, str] = field(default_factory=dict[str, str])
88+
autoscaling: dict[str, Union[str, float]] = field(default_factory=dict[str, Union[str, float]])
8889
health_check_path: str = "/health"
8990
termination_grace_period_seconds: int = 300
9091
volume_mounts: list[VolumeMount] = field(default_factory=list[VolumeMount])
@@ -93,7 +94,7 @@ class DeployConfig:
9394
def from_dict(cls, data: dict[str, Any]) -> DeployConfig:
9495
deploy_config = {k: v for k, v in data.items() if k in cls.__annotations__}
9596
if isinstance((mounts := deploy_config.get("volume_mounts")), list):
96-
deploy_config["volume_mounts"] = [VolumeMount.from_dict(vm) for vm in mounts] # pyright: ignore
97+
deploy_config["volume_mounts"] = [VolumeMount.from_dict(vm) for vm in cast(list[dict[str, Any]], mounts)]
9798
return cls(**deploy_config)
9899

99100

@@ -133,7 +134,7 @@ def validate(value: Any, value_type: type, path: str = "") -> str | None:
133134
return None
134135

135136
if not isinstance(value, value_type):
136-
return f"{path}: expected {type(value).__name__}, got {value!r}"
137+
return f"{path}: expected {value_type.__name__}, got {value!r}" # type: ignore[union-attr]
137138
return None
138139

139140

@@ -196,7 +197,7 @@ def load(cls, data: dict[str, Any], path: Path) -> Config:
196197
else:
197198
jig_config = data
198199
if name := jig_config.get("name"):
199-
tip = "update `name` in {path}"
200+
tip = f"update `name` in {path}"
200201
else:
201202
name = path.resolve().parent.name
202203
tip = f"rename your folder or add `name` to {path}"

src/together/lib/cli/api/beta/jig/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def format_deployment_status(d: Deployment) -> str:
8989
events_status = "\nReplica Events:\n"
9090
images = set(map(lambda x: x.image or "-", d.replica_events.values()))
9191
for image in reversed(sorted(images)):
92-
events = filter(lambda x: ((x[1].image or "-") == image), d.replica_events.items())
92+
events = filter(lambda x: (x[1].image or "-") == image, d.replica_events.items())
9393
events_status += f"{_image_tag(image)}:\n"
9494
for replica_id, event in events:
9595
events_status += f" {replica_id}: "

src/together/lib/cli/api/beta/jig/volumes.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import time
77
import asyncio
88
import itertools
9-
from typing import Any
9+
from typing import Any, cast
1010
from pathlib import Path
1111

1212
import click
@@ -107,13 +107,13 @@ async def spinner_updater(self) -> None:
107107
self.update_progress()
108108
await asyncio.sleep(0.1)
109109

110-
async def upload_files(self, source_path: Path, volume_name: str) -> None:
110+
async def upload_files(self, source_path: Path, volume_name: str, content_version: int) -> None:
111111
"""Upload all files from source directory with progress tracking"""
112112
# these require a running event loop
113113
self.semaphore = asyncio.Semaphore(UPLOAD_CONCURRENCY_LIMIT)
114114
self.progress_lock = asyncio.Lock()
115115

116-
source_prefix = f"{volume_name}/{source_path.name}"
116+
source_prefix = f"{volume_name}/{content_version}"
117117
files_to_upload: list[tuple[Path, str, int]] = []
118118

119119
for file_path in source_path.rglob("*"):
@@ -296,7 +296,8 @@ async def _create_volume(client: Together, name: str, source: str) -> None:
296296
if not source_path.is_dir():
297297
raise ValueError(f"Source path must be a directory: {source}")
298298

299-
source_prefix = f"{name}/{source_path.name}"
299+
content_version = 0
300+
source_prefix = f"{name}/{content_version}"
300301

301302
click.echo(f"\N{ROCKET} Creating volume '{name}' with source prefix '{source_prefix}'")
302303
try:
@@ -310,7 +311,7 @@ async def _create_volume(client: Together, name: str, source: str) -> None:
310311
raise RuntimeError(f"Failed to create volume: {e}") from e
311312

312313
try:
313-
await Uploader(client).upload_files(source_path, volume_name=name)
314+
await Uploader(client).upload_files(source_path, volume_name=name, content_version=content_version)
314315
except Exception as e:
315316
click.echo(f"\N{CROSS MARK} Upload failed: {e}")
316317
click.echo(f"\N{WASTEBASKET} Cleaning up volume '{name}'")
@@ -330,16 +331,20 @@ async def _update_volume(client: Together, name: str, source: str) -> None:
330331
raise ValueError(f"Source path must be a directory: {source}")
331332

332333
try:
333-
client.beta.jig.volumes.retrieve(name)
334+
response = client.beta.jig.volumes.with_raw_response.retrieve(name)
335+
volume_data = response.json()
334336
except APIStatusError as e:
335337
if hasattr(e, "status_code") and e.status_code == 404:
336338
raise ValueError(f"Volume '{name}' does not exist") from e
337339
raise
338340

339-
source_prefix = f"{name}/{source_path.name}"
341+
volume_dict = cast(dict[str, Any], volume_data)
342+
current_version: int = int(volume_dict.get("current_version", 0))
343+
version: int = current_version + 1
344+
source_prefix = f"{name}/{version}"
340345

341346
click.echo(f"\N{INFORMATION SOURCE} Uploading files for volume '{name}'")
342-
await Uploader(client).upload_files(source_path, volume_name=name)
347+
await Uploader(client).upload_files(source_path, volume_name=name, content_version=version)
343348

344349
click.echo(f"\N{INFORMATION SOURCE} Updating volume '{name}' with source prefix '{source_prefix}'")
345350
client.beta.jig.volumes.update(

0 commit comments

Comments
 (0)