flyte 0.2.0b4__py3-none-any.whl → 0.2.0b7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flyte might be problematic. Click here for more details.
- flyte/__init__.py +2 -1
- flyte/_build.py +3 -2
- flyte/_code_bundle/_utils.py +0 -16
- flyte/_code_bundle/bundle.py +1 -1
- flyte/_deploy.py +4 -4
- flyte/_initialize.py +69 -26
- flyte/_internal/controllers/remote/_core.py +1 -1
- flyte/_protos/workflow/common_pb2.py +27 -0
- flyte/_protos/workflow/common_pb2.pyi +14 -0
- flyte/_protos/workflow/common_pb2_grpc.py +4 -0
- flyte/_protos/workflow/run_definition_pb2.py +14 -14
- flyte/_protos/workflow/run_definition_pb2.pyi +4 -2
- flyte/_protos/workflow/task_definition_pb2.py +14 -13
- flyte/_protos/workflow/task_definition_pb2.pyi +7 -3
- flyte/_run.py +7 -5
- flyte/_trace.py +1 -6
- flyte/_version.py +2 -2
- flyte/cli/_common.py +23 -15
- flyte/cli/_run.py +12 -6
- flyte/cli/main.py +15 -9
- flyte/config/__init__.py +2 -189
- flyte/config/_config.py +181 -172
- flyte/config/_internal.py +1 -1
- flyte/config/_reader.py +207 -0
- flyte/io/_dir.py +2 -2
- flyte/io/_file.py +1 -4
- flyte/remote/_data.py +3 -3
- flyte/remote/_logs.py +49 -26
- flyte/remote/_project.py +8 -9
- flyte/remote/_run.py +106 -61
- flyte/remote/_secret.py +12 -12
- flyte/remote/_task.py +3 -3
- flyte/report/_report.py +4 -4
- flyte/syncify/__init__.py +5 -0
- flyte/syncify/_api.py +277 -0
- flyte-0.2.0b7.dist-info/METADATA +156 -0
- {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/RECORD +40 -35
- flyte/_api_commons.py +0 -3
- flyte-0.2.0b4.dist-info/METADATA +0 -179
- {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/WHEEL +0 -0
- {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/entry_points.txt +0 -0
- {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/top_level.txt +0 -0
flyte/remote/_data.py
CHANGED
|
@@ -15,7 +15,7 @@ import httpx
|
|
|
15
15
|
from flyteidl.service import dataproxy_pb2
|
|
16
16
|
from google.protobuf import duration_pb2
|
|
17
17
|
|
|
18
|
-
from flyte._initialize import CommonInit, get_client, get_common_config
|
|
18
|
+
from flyte._initialize import CommonInit, ensure_client, get_client, get_common_config
|
|
19
19
|
from flyte.errors import RuntimeSystemError
|
|
20
20
|
|
|
21
21
|
_UPLOAD_EXPIRES_IN = timedelta(seconds=60)
|
|
@@ -109,7 +109,6 @@ async def _upload_single_file(
|
|
|
109
109
|
return str_digest, resp.native_url
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
@requires_client
|
|
113
112
|
async def upload_file(fp: Path, verify: bool = True) -> Tuple[str, str]:
|
|
114
113
|
"""
|
|
115
114
|
Uploads a file to a remote location and returns the remote URI.
|
|
@@ -119,13 +118,13 @@ async def upload_file(fp: Path, verify: bool = True) -> Tuple[str, str]:
|
|
|
119
118
|
:return: A tuple containing the MD5 digest and the remote URI.
|
|
120
119
|
"""
|
|
121
120
|
# This is a placeholder implementation. Replace with actual upload logic.
|
|
121
|
+
ensure_client()
|
|
122
122
|
cfg = get_common_config()
|
|
123
123
|
if not fp.is_file():
|
|
124
124
|
raise ValueError(f"{fp} is not a single file, upload arg must be a single file.")
|
|
125
125
|
return await _upload_single_file(cfg, fp, verify=verify)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
@requires_client
|
|
129
128
|
async def upload_dir(dir_path: Path, verify: bool = True) -> str:
|
|
130
129
|
"""
|
|
131
130
|
Uploads a directory to a remote location and returns the remote URI.
|
|
@@ -135,6 +134,7 @@ async def upload_dir(dir_path: Path, verify: bool = True) -> str:
|
|
|
135
134
|
:return: The remote URI of the uploaded directory.
|
|
136
135
|
"""
|
|
137
136
|
# This is a placeholder implementation. Replace with actual upload logic.
|
|
137
|
+
ensure_client()
|
|
138
138
|
cfg = get_common_config()
|
|
139
139
|
if not dir_path.is_dir():
|
|
140
140
|
raise ValueError(f"{dir_path} is not a directory, upload arg must be a directory.")
|
flyte/remote/_logs.py
CHANGED
|
@@ -9,11 +9,11 @@ from rich.live import Live
|
|
|
9
9
|
from rich.panel import Panel
|
|
10
10
|
from rich.text import Text
|
|
11
11
|
|
|
12
|
-
from flyte.
|
|
13
|
-
from flyte._initialize import get_client, requires_client
|
|
12
|
+
from flyte._initialize import ensure_client, get_client
|
|
14
13
|
from flyte._protos.logs.dataplane import payload_pb2
|
|
15
14
|
from flyte._protos.workflow import run_definition_pb2, run_logs_service_pb2
|
|
16
15
|
from flyte.errors import LogsNotYetAvailableError
|
|
16
|
+
from flyte.syncify import syncify
|
|
17
17
|
|
|
18
18
|
style_map = {
|
|
19
19
|
payload_pb2.LogLineOriginator.SYSTEM: "bold magenta",
|
|
@@ -49,6 +49,7 @@ class AsyncLogViewer:
|
|
|
49
49
|
name: str = "Logs",
|
|
50
50
|
show_ts: bool = False,
|
|
51
51
|
filter_system: bool = False,
|
|
52
|
+
panel: bool = False,
|
|
52
53
|
):
|
|
53
54
|
self.console = Console()
|
|
54
55
|
self.log_source = log_source
|
|
@@ -58,12 +59,15 @@ class AsyncLogViewer:
|
|
|
58
59
|
self.show_ts = show_ts
|
|
59
60
|
self.total_lines = 0
|
|
60
61
|
self.filter_flyte = filter_system
|
|
62
|
+
self.panel = panel
|
|
61
63
|
|
|
62
|
-
def _render(self) -> Panel:
|
|
64
|
+
def _render(self) -> Panel | Text:
|
|
63
65
|
log_text = Text()
|
|
64
66
|
for line in self.lines:
|
|
65
67
|
log_text.append(line)
|
|
66
|
-
|
|
68
|
+
if self.panel:
|
|
69
|
+
return Panel(log_text, title=self.name, border_style="yellow")
|
|
70
|
+
return log_text
|
|
67
71
|
|
|
68
72
|
async def run(self):
|
|
69
73
|
with Live(self._render(), refresh_per_second=20, console=self.console) as live:
|
|
@@ -78,6 +82,8 @@ class AsyncLogViewer:
|
|
|
78
82
|
pass
|
|
79
83
|
except KeyboardInterrupt:
|
|
80
84
|
pass
|
|
85
|
+
except StopAsyncIteration:
|
|
86
|
+
self.console.print("[dim]Log stream ended.[/dim]")
|
|
81
87
|
except LogsNotYetAvailableError as e:
|
|
82
88
|
self.console.print(f"[red]Error:[/red] {e}")
|
|
83
89
|
live.update("")
|
|
@@ -86,35 +92,47 @@ class AsyncLogViewer:
|
|
|
86
92
|
|
|
87
93
|
@dataclass
|
|
88
94
|
class Logs:
|
|
95
|
+
@syncify
|
|
89
96
|
@classmethod
|
|
90
|
-
@requires_client
|
|
91
|
-
@syncer.wrap
|
|
92
97
|
async def tail(
|
|
93
|
-
cls,
|
|
98
|
+
cls,
|
|
99
|
+
action_id: run_definition_pb2.ActionIdentifier,
|
|
100
|
+
attempt: int = 1,
|
|
101
|
+
retry: int = 3,
|
|
94
102
|
) -> AsyncGenerator[payload_pb2.LogLine, None]:
|
|
95
103
|
"""
|
|
96
104
|
Tail the logs for a given action ID and attempt.
|
|
97
105
|
:param action_id: The action ID to tail logs for.
|
|
98
106
|
:param attempt: The attempt number (default is 0).
|
|
99
107
|
"""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
for log in log_set.logs:
|
|
107
|
-
for line in log.lines:
|
|
108
|
-
yield line
|
|
109
|
-
except asyncio.CancelledError:
|
|
110
|
-
pass
|
|
111
|
-
except KeyboardInterrupt:
|
|
112
|
-
pass
|
|
113
|
-
except grpc.aio.AioRpcError as e:
|
|
114
|
-
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
115
|
-
raise LogsNotYetAvailableError(
|
|
116
|
-
f"Log stream not available for action {action_id.name} in run {action_id.run.name}."
|
|
108
|
+
ensure_client()
|
|
109
|
+
retries = 0
|
|
110
|
+
while True:
|
|
111
|
+
try:
|
|
112
|
+
resp = get_client().logs_service.TailLogs(
|
|
113
|
+
run_logs_service_pb2.TailLogsRequest(action_id=action_id, attempt=attempt)
|
|
117
114
|
)
|
|
115
|
+
async for log_set in resp:
|
|
116
|
+
if log_set.logs:
|
|
117
|
+
for log in log_set.logs:
|
|
118
|
+
for line in log.lines:
|
|
119
|
+
yield line
|
|
120
|
+
return
|
|
121
|
+
except asyncio.CancelledError:
|
|
122
|
+
return
|
|
123
|
+
except KeyboardInterrupt:
|
|
124
|
+
return
|
|
125
|
+
except StopAsyncIteration:
|
|
126
|
+
return
|
|
127
|
+
except grpc.aio.AioRpcError as e:
|
|
128
|
+
retries += 1
|
|
129
|
+
if retries >= retry:
|
|
130
|
+
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
131
|
+
raise LogsNotYetAvailableError(
|
|
132
|
+
f"Log stream not available for action {action_id.name} in run {action_id.run.name}."
|
|
133
|
+
)
|
|
134
|
+
else:
|
|
135
|
+
await asyncio.sleep(1)
|
|
118
136
|
|
|
119
137
|
@classmethod
|
|
120
138
|
async def create_viewer(
|
|
@@ -125,6 +143,7 @@ class Logs:
|
|
|
125
143
|
show_ts: bool = False,
|
|
126
144
|
raw: bool = False,
|
|
127
145
|
filter_system: bool = False,
|
|
146
|
+
panel: bool = False,
|
|
128
147
|
):
|
|
129
148
|
"""
|
|
130
149
|
Create a log viewer for a given action ID and attempt.
|
|
@@ -135,19 +154,23 @@ class Logs:
|
|
|
135
154
|
:param show_ts: Whether to show timestamps in the logs.
|
|
136
155
|
:param raw: if True, return the raw log lines instead of a viewer.
|
|
137
156
|
:param filter_system: Whether to filter log lines based on system logs.
|
|
157
|
+
:param panel: Whether to use a panel for the log viewer. only applicable if raw is False.
|
|
138
158
|
"""
|
|
159
|
+
if attempt < 1:
|
|
160
|
+
raise ValueError("Attempt number must be greater than 0.")
|
|
139
161
|
if raw:
|
|
140
162
|
console = Console()
|
|
141
|
-
async for line in cls.tail.aio(
|
|
163
|
+
async for line in cls.tail.aio(action_id=action_id, attempt=attempt):
|
|
142
164
|
line_text = _format_line(line, show_ts=show_ts, filter_system=filter_system)
|
|
143
165
|
if line_text:
|
|
144
166
|
console.print(line_text, end="")
|
|
145
167
|
return
|
|
146
168
|
viewer = AsyncLogViewer(
|
|
147
|
-
log_source=cls.tail.aio(
|
|
169
|
+
log_source=cls.tail.aio(action_id=action_id, attempt=attempt),
|
|
148
170
|
max_lines=max_lines,
|
|
149
171
|
show_ts=show_ts,
|
|
150
172
|
name=f"{action_id.run.name}:{action_id.name} ({attempt})",
|
|
151
173
|
filter_system=filter_system,
|
|
174
|
+
panel=panel,
|
|
152
175
|
)
|
|
153
176
|
await viewer.run()
|
flyte/remote/_project.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import typing
|
|
4
3
|
from dataclasses import dataclass
|
|
5
|
-
from typing import
|
|
4
|
+
from typing import AsyncIterator, Iterator, Literal, Tuple, Union
|
|
6
5
|
|
|
7
6
|
import rich.repr
|
|
8
7
|
from flyteidl.admin import common_pb2, project_pb2
|
|
9
8
|
|
|
10
|
-
from flyte.
|
|
11
|
-
from flyte.
|
|
9
|
+
from flyte._initialize import ensure_client, get_client, get_common_config
|
|
10
|
+
from flyte.syncify import syncify
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass
|
|
@@ -19,9 +18,8 @@ class Project:
|
|
|
19
18
|
|
|
20
19
|
_pb2: project_pb2.Project
|
|
21
20
|
|
|
21
|
+
@syncify
|
|
22
22
|
@classmethod
|
|
23
|
-
@requires_client
|
|
24
|
-
@syncer.wrap
|
|
25
23
|
async def get(cls, name: str, org: str | None = None) -> Project:
|
|
26
24
|
"""
|
|
27
25
|
Get a run by its ID or name. If both are provided, the ID will take precedence.
|
|
@@ -29,6 +27,7 @@ class Project:
|
|
|
29
27
|
:param name: The name of the project.
|
|
30
28
|
:param org: The organization of the project (if applicable).
|
|
31
29
|
"""
|
|
30
|
+
ensure_client()
|
|
32
31
|
service = get_client().project_domain_service # type: ignore
|
|
33
32
|
resp = await service.GetProject(
|
|
34
33
|
project_pb2.ProjectGetRequest(
|
|
@@ -38,14 +37,13 @@ class Project:
|
|
|
38
37
|
)
|
|
39
38
|
return cls(resp)
|
|
40
39
|
|
|
40
|
+
@syncify
|
|
41
41
|
@classmethod
|
|
42
|
-
@requires_client
|
|
43
|
-
@syncer.wrap
|
|
44
42
|
async def listall(
|
|
45
43
|
cls,
|
|
46
44
|
filters: str | None = None,
|
|
47
45
|
sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
|
|
48
|
-
) ->
|
|
46
|
+
) -> Union[AsyncIterator[Project], Iterator[Project]]:
|
|
49
47
|
"""
|
|
50
48
|
Get a run by its ID or name. If both are provided, the ID will take precedence.
|
|
51
49
|
|
|
@@ -53,6 +51,7 @@ class Project:
|
|
|
53
51
|
:param sort_by: The sorting criteria for the project list, in the format (field, order).
|
|
54
52
|
:return: An iterator of projects.
|
|
55
53
|
"""
|
|
54
|
+
ensure_client()
|
|
56
55
|
token = None
|
|
57
56
|
sort_by = sort_by or ("created_at", "asc")
|
|
58
57
|
sort_pb2 = common_pb2.Sort(
|