Skip to content

Commit 51e90db

Browse files
committed
Add type for build log message
1 parent e1a6dde commit 51e90db

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

src/fastapi_cloud_cli/commands/deploy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def _wait_for_deployment(
343343
for log in client.stream_build_logs(deployment.id):
344344
time_elapsed = time.monotonic() - started_at
345345

346-
if log.type == BuildLogType.message and log.message:
346+
if log.type == BuildLogType.message:
347347
progress.log(Text.from_ansi(log.message.rstrip()))
348348

349349
if log.type == BuildLogType.complete:

src/fastapi_cloud_cli/utils/api.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from contextlib import contextmanager
44
from datetime import timedelta
55
from enum import Enum
6-
from typing import ContextManager, Generator, Optional
6+
from typing import ContextManager, Generator, Literal, Optional
77

88
import httpx
9-
from pydantic import BaseModel, ValidationError
9+
from pydantic import BaseModel, Field, TypeAdapter, ValidationError
10+
from typing_extensions import Annotated
1011

1112
from fastapi_cloud_cli import __version__
1213
from fastapi_cloud_cli.config import Settings
@@ -18,7 +19,8 @@
1819
BUILD_LOG_TIMEOUT = timedelta(minutes=5)
1920

2021

21-
class BuildLogError(Exception): ...
22+
class BuildLogError(Exception):
23+
pass
2224

2325

2426
class BuildLogType(str, Enum):
@@ -30,11 +32,28 @@ class BuildLogType(str, Enum):
3032

3133

3234
class BuildLogLine(BaseModel):
33-
type: BuildLogType
35+
type: Literal[
36+
BuildLogType.complete,
37+
BuildLogType.failed,
38+
BuildLogType.timeout,
39+
BuildLogType.heartbeat,
40+
]
3441
message: Optional[str] = None
3542
id: Optional[str] = None
3643

3744

45+
class BuildLogLineMessage(BaseModel):
46+
type: Literal[BuildLogType.message] = BuildLogType.message
47+
message: str
48+
id: Optional[str] = None
49+
50+
51+
# check pydantic v1
52+
BuildLogAdapter = TypeAdapter[BuildLogLineMessage | BuildLogLine](
53+
Annotated[BuildLogLineMessage | BuildLogLine, Field(discriminator="type")]
54+
)
55+
56+
3857
@contextmanager
3958
def attempt(attempt_number: int) -> Generator[None, None, None]:
4059
def _backoff() -> None:
@@ -108,7 +127,7 @@ def __init__(self) -> None:
108127

109128
def stream_build_logs(
110129
self, deployment_id: str
111-
) -> Generator[BuildLogLine, None, None]:
130+
) -> Generator[BuildLogLineMessage | BuildLogLine, None, None]:
112131
last_id = None
113132

114133
for attempt in attempts(BUILD_LOG_MAX_RETRIES, BUILD_LOG_TIMEOUT):
@@ -158,9 +177,11 @@ def stream_build_logs(
158177
# Exhausted retries without getting any response
159178
raise BuildLogError(f"Failed after {BUILD_LOG_MAX_RETRIES} attempts")
160179

161-
def _parse_log_line(self, line: str) -> Optional[BuildLogLine]:
180+
def _parse_log_line(
181+
self, line: str
182+
) -> Optional[BuildLogLineMessage | BuildLogLine]:
162183
try:
163-
return BuildLogLine.model_validate_json(line)
184+
return BuildLogAdapter.validate_json(line)
164185
except ValidationError as e:
165186
logger.debug("Skipping malformed log: %s (error: %s)", line[:100], e)
166187
return None

0 commit comments

Comments
 (0)