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.

Files changed (42) hide show
  1. flyte/__init__.py +2 -1
  2. flyte/_build.py +3 -2
  3. flyte/_code_bundle/_utils.py +0 -16
  4. flyte/_code_bundle/bundle.py +1 -1
  5. flyte/_deploy.py +4 -4
  6. flyte/_initialize.py +69 -26
  7. flyte/_internal/controllers/remote/_core.py +1 -1
  8. flyte/_protos/workflow/common_pb2.py +27 -0
  9. flyte/_protos/workflow/common_pb2.pyi +14 -0
  10. flyte/_protos/workflow/common_pb2_grpc.py +4 -0
  11. flyte/_protos/workflow/run_definition_pb2.py +14 -14
  12. flyte/_protos/workflow/run_definition_pb2.pyi +4 -2
  13. flyte/_protos/workflow/task_definition_pb2.py +14 -13
  14. flyte/_protos/workflow/task_definition_pb2.pyi +7 -3
  15. flyte/_run.py +7 -5
  16. flyte/_trace.py +1 -6
  17. flyte/_version.py +2 -2
  18. flyte/cli/_common.py +23 -15
  19. flyte/cli/_run.py +12 -6
  20. flyte/cli/main.py +15 -9
  21. flyte/config/__init__.py +2 -189
  22. flyte/config/_config.py +181 -172
  23. flyte/config/_internal.py +1 -1
  24. flyte/config/_reader.py +207 -0
  25. flyte/io/_dir.py +2 -2
  26. flyte/io/_file.py +1 -4
  27. flyte/remote/_data.py +3 -3
  28. flyte/remote/_logs.py +49 -26
  29. flyte/remote/_project.py +8 -9
  30. flyte/remote/_run.py +106 -61
  31. flyte/remote/_secret.py +12 -12
  32. flyte/remote/_task.py +3 -3
  33. flyte/report/_report.py +4 -4
  34. flyte/syncify/__init__.py +5 -0
  35. flyte/syncify/_api.py +277 -0
  36. flyte-0.2.0b7.dist-info/METADATA +156 -0
  37. {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/RECORD +40 -35
  38. flyte/_api_commons.py +0 -3
  39. flyte-0.2.0b4.dist-info/METADATA +0 -179
  40. {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/WHEEL +0 -0
  41. {flyte-0.2.0b4.dist-info → flyte-0.2.0b7.dist-info}/entry_points.txt +0 -0
  42. {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, requires_client
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._api_commons import syncer
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
- return Panel(log_text, title=self.name, border_style="yellow")
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, action_id: run_definition_pb2.ActionIdentifier, attempt: int = 1
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
- try:
101
- resp = get_client().logs_service.TailLogs(
102
- run_logs_service_pb2.TailLogsRequest(action_id=action_id, attempt=attempt)
103
- )
104
- async for log_set in resp:
105
- if log_set.logs:
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(cls, action_id=action_id, attempt=attempt):
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(cls, action_id=action_id, attempt=attempt),
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 AsyncGenerator, Literal, Tuple
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._api_commons import syncer
11
- from flyte._initialize import get_client, get_common_config, requires_client
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
- ) -> typing.Union[typing.Iterator[Project], AsyncGenerator[Project, None]]:
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(