flyte 0.2.0b1__py3-none-any.whl → 2.0.0b46__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.
Files changed (266) hide show
  1. flyte/__init__.py +83 -30
  2. flyte/_bin/connect.py +61 -0
  3. flyte/_bin/debug.py +38 -0
  4. flyte/_bin/runtime.py +87 -19
  5. flyte/_bin/serve.py +351 -0
  6. flyte/_build.py +3 -2
  7. flyte/_cache/cache.py +6 -5
  8. flyte/_cache/local_cache.py +216 -0
  9. flyte/_code_bundle/_ignore.py +31 -5
  10. flyte/_code_bundle/_packaging.py +42 -11
  11. flyte/_code_bundle/_utils.py +57 -34
  12. flyte/_code_bundle/bundle.py +130 -27
  13. flyte/_constants.py +1 -0
  14. flyte/_context.py +21 -5
  15. flyte/_custom_context.py +73 -0
  16. flyte/_debug/constants.py +37 -0
  17. flyte/_debug/utils.py +17 -0
  18. flyte/_debug/vscode.py +315 -0
  19. flyte/_deploy.py +396 -75
  20. flyte/_deployer.py +109 -0
  21. flyte/_environment.py +94 -11
  22. flyte/_excepthook.py +37 -0
  23. flyte/_group.py +2 -1
  24. flyte/_hash.py +1 -16
  25. flyte/_image.py +544 -231
  26. flyte/_initialize.py +456 -316
  27. flyte/_interface.py +40 -5
  28. flyte/_internal/controllers/__init__.py +22 -8
  29. flyte/_internal/controllers/_local_controller.py +159 -35
  30. flyte/_internal/controllers/_trace.py +18 -10
  31. flyte/_internal/controllers/remote/__init__.py +38 -9
  32. flyte/_internal/controllers/remote/_action.py +82 -12
  33. flyte/_internal/controllers/remote/_client.py +6 -2
  34. flyte/_internal/controllers/remote/_controller.py +290 -64
  35. flyte/_internal/controllers/remote/_core.py +155 -95
  36. flyte/_internal/controllers/remote/_informer.py +40 -20
  37. flyte/_internal/controllers/remote/_service_protocol.py +2 -2
  38. flyte/_internal/imagebuild/__init__.py +2 -10
  39. flyte/_internal/imagebuild/docker_builder.py +391 -84
  40. flyte/_internal/imagebuild/image_builder.py +111 -55
  41. flyte/_internal/imagebuild/remote_builder.py +409 -0
  42. flyte/_internal/imagebuild/utils.py +79 -0
  43. flyte/_internal/resolvers/_app_env_module.py +92 -0
  44. flyte/_internal/resolvers/_task_module.py +5 -38
  45. flyte/_internal/resolvers/app_env.py +26 -0
  46. flyte/_internal/resolvers/common.py +8 -1
  47. flyte/_internal/resolvers/default.py +2 -2
  48. flyte/_internal/runtime/convert.py +319 -36
  49. flyte/_internal/runtime/entrypoints.py +106 -18
  50. flyte/_internal/runtime/io.py +71 -23
  51. flyte/_internal/runtime/resources_serde.py +21 -7
  52. flyte/_internal/runtime/reuse.py +125 -0
  53. flyte/_internal/runtime/rusty.py +196 -0
  54. flyte/_internal/runtime/task_serde.py +239 -66
  55. flyte/_internal/runtime/taskrunner.py +48 -8
  56. flyte/_internal/runtime/trigger_serde.py +162 -0
  57. flyte/_internal/runtime/types_serde.py +7 -16
  58. flyte/_keyring/file.py +115 -0
  59. flyte/_link.py +30 -0
  60. flyte/_logging.py +241 -42
  61. flyte/_map.py +312 -0
  62. flyte/_metrics.py +59 -0
  63. flyte/_module.py +74 -0
  64. flyte/_pod.py +30 -0
  65. flyte/_resources.py +296 -33
  66. flyte/_retry.py +1 -7
  67. flyte/_reusable_environment.py +72 -7
  68. flyte/_run.py +462 -132
  69. flyte/_secret.py +47 -11
  70. flyte/_serve.py +333 -0
  71. flyte/_task.py +245 -56
  72. flyte/_task_environment.py +219 -97
  73. flyte/_task_plugins.py +47 -0
  74. flyte/_tools.py +8 -8
  75. flyte/_trace.py +15 -24
  76. flyte/_trigger.py +1027 -0
  77. flyte/_utils/__init__.py +12 -1
  78. flyte/_utils/asyn.py +3 -1
  79. flyte/_utils/async_cache.py +139 -0
  80. flyte/_utils/coro_management.py +5 -4
  81. flyte/_utils/description_parser.py +19 -0
  82. flyte/_utils/docker_credentials.py +173 -0
  83. flyte/_utils/helpers.py +45 -19
  84. flyte/_utils/module_loader.py +123 -0
  85. flyte/_utils/org_discovery.py +57 -0
  86. flyte/_utils/uv_script_parser.py +8 -1
  87. flyte/_version.py +16 -3
  88. flyte/app/__init__.py +27 -0
  89. flyte/app/_app_environment.py +362 -0
  90. flyte/app/_connector_environment.py +40 -0
  91. flyte/app/_deploy.py +130 -0
  92. flyte/app/_parameter.py +343 -0
  93. flyte/app/_runtime/__init__.py +3 -0
  94. flyte/app/_runtime/app_serde.py +383 -0
  95. flyte/app/_types.py +113 -0
  96. flyte/app/extras/__init__.py +9 -0
  97. flyte/app/extras/_auth_middleware.py +217 -0
  98. flyte/app/extras/_fastapi.py +93 -0
  99. flyte/app/extras/_model_loader/__init__.py +3 -0
  100. flyte/app/extras/_model_loader/config.py +7 -0
  101. flyte/app/extras/_model_loader/loader.py +288 -0
  102. flyte/cli/__init__.py +12 -0
  103. flyte/cli/_abort.py +28 -0
  104. flyte/cli/_build.py +114 -0
  105. flyte/cli/_common.py +493 -0
  106. flyte/cli/_create.py +371 -0
  107. flyte/cli/_delete.py +45 -0
  108. flyte/cli/_deploy.py +401 -0
  109. flyte/cli/_gen.py +316 -0
  110. flyte/cli/_get.py +446 -0
  111. flyte/cli/_option.py +33 -0
  112. flyte/{_cli → cli}/_params.py +57 -17
  113. flyte/cli/_plugins.py +209 -0
  114. flyte/cli/_prefetch.py +292 -0
  115. flyte/cli/_run.py +690 -0
  116. flyte/cli/_serve.py +338 -0
  117. flyte/cli/_update.py +86 -0
  118. flyte/cli/_user.py +20 -0
  119. flyte/cli/main.py +246 -0
  120. flyte/config/__init__.py +2 -167
  121. flyte/config/_config.py +215 -163
  122. flyte/config/_internal.py +10 -1
  123. flyte/config/_reader.py +225 -0
  124. flyte/connectors/__init__.py +11 -0
  125. flyte/connectors/_connector.py +330 -0
  126. flyte/connectors/_server.py +194 -0
  127. flyte/connectors/utils.py +159 -0
  128. flyte/errors.py +134 -2
  129. flyte/extend.py +24 -0
  130. flyte/extras/_container.py +69 -56
  131. flyte/git/__init__.py +3 -0
  132. flyte/git/_config.py +279 -0
  133. flyte/io/__init__.py +8 -1
  134. flyte/io/{structured_dataset → _dataframe}/__init__.py +32 -30
  135. flyte/io/{structured_dataset → _dataframe}/basic_dfs.py +75 -68
  136. flyte/io/{structured_dataset/structured_dataset.py → _dataframe/dataframe.py} +207 -242
  137. flyte/io/_dir.py +575 -113
  138. flyte/io/_file.py +587 -141
  139. flyte/io/_hashing_io.py +342 -0
  140. flyte/io/extend.py +7 -0
  141. flyte/models.py +635 -0
  142. flyte/prefetch/__init__.py +22 -0
  143. flyte/prefetch/_hf_model.py +563 -0
  144. flyte/remote/__init__.py +14 -3
  145. flyte/remote/_action.py +879 -0
  146. flyte/remote/_app.py +346 -0
  147. flyte/remote/_auth_metadata.py +42 -0
  148. flyte/remote/_client/_protocols.py +62 -4
  149. flyte/remote/_client/auth/_auth_utils.py +19 -0
  150. flyte/remote/_client/auth/_authenticators/base.py +8 -2
  151. flyte/remote/_client/auth/_authenticators/device_code.py +4 -5
  152. flyte/remote/_client/auth/_authenticators/factory.py +4 -0
  153. flyte/remote/_client/auth/_authenticators/passthrough.py +79 -0
  154. flyte/remote/_client/auth/_authenticators/pkce.py +17 -18
  155. flyte/remote/_client/auth/_channel.py +47 -18
  156. flyte/remote/_client/auth/_client_config.py +5 -3
  157. flyte/remote/_client/auth/_keyring.py +15 -2
  158. flyte/remote/_client/auth/_token_client.py +3 -3
  159. flyte/remote/_client/controlplane.py +206 -18
  160. flyte/remote/_common.py +66 -0
  161. flyte/remote/_data.py +107 -22
  162. flyte/remote/_logs.py +116 -33
  163. flyte/remote/_project.py +21 -19
  164. flyte/remote/_run.py +164 -631
  165. flyte/remote/_secret.py +72 -29
  166. flyte/remote/_task.py +387 -46
  167. flyte/remote/_trigger.py +368 -0
  168. flyte/remote/_user.py +43 -0
  169. flyte/report/_report.py +10 -6
  170. flyte/storage/__init__.py +13 -1
  171. flyte/storage/_config.py +237 -0
  172. flyte/storage/_parallel_reader.py +289 -0
  173. flyte/storage/_storage.py +268 -59
  174. flyte/syncify/__init__.py +56 -0
  175. flyte/syncify/_api.py +414 -0
  176. flyte/types/__init__.py +39 -0
  177. flyte/types/_interface.py +22 -7
  178. flyte/{io/pickle/transformer.py → types/_pickle.py} +37 -9
  179. flyte/types/_string_literals.py +8 -9
  180. flyte/types/_type_engine.py +226 -126
  181. flyte/types/_utils.py +1 -1
  182. flyte-2.0.0b46.data/scripts/debug.py +38 -0
  183. flyte-2.0.0b46.data/scripts/runtime.py +194 -0
  184. flyte-2.0.0b46.dist-info/METADATA +352 -0
  185. flyte-2.0.0b46.dist-info/RECORD +221 -0
  186. flyte-2.0.0b46.dist-info/entry_points.txt +8 -0
  187. flyte-2.0.0b46.dist-info/licenses/LICENSE +201 -0
  188. flyte/_api_commons.py +0 -3
  189. flyte/_cli/_common.py +0 -299
  190. flyte/_cli/_create.py +0 -42
  191. flyte/_cli/_delete.py +0 -23
  192. flyte/_cli/_deploy.py +0 -140
  193. flyte/_cli/_get.py +0 -235
  194. flyte/_cli/_run.py +0 -174
  195. flyte/_cli/main.py +0 -98
  196. flyte/_datastructures.py +0 -342
  197. flyte/_internal/controllers/pbhash.py +0 -39
  198. flyte/_protos/common/authorization_pb2.py +0 -66
  199. flyte/_protos/common/authorization_pb2.pyi +0 -108
  200. flyte/_protos/common/authorization_pb2_grpc.py +0 -4
  201. flyte/_protos/common/identifier_pb2.py +0 -71
  202. flyte/_protos/common/identifier_pb2.pyi +0 -82
  203. flyte/_protos/common/identifier_pb2_grpc.py +0 -4
  204. flyte/_protos/common/identity_pb2.py +0 -48
  205. flyte/_protos/common/identity_pb2.pyi +0 -72
  206. flyte/_protos/common/identity_pb2_grpc.py +0 -4
  207. flyte/_protos/common/list_pb2.py +0 -36
  208. flyte/_protos/common/list_pb2.pyi +0 -69
  209. flyte/_protos/common/list_pb2_grpc.py +0 -4
  210. flyte/_protos/common/policy_pb2.py +0 -37
  211. flyte/_protos/common/policy_pb2.pyi +0 -27
  212. flyte/_protos/common/policy_pb2_grpc.py +0 -4
  213. flyte/_protos/common/role_pb2.py +0 -37
  214. flyte/_protos/common/role_pb2.pyi +0 -53
  215. flyte/_protos/common/role_pb2_grpc.py +0 -4
  216. flyte/_protos/common/runtime_version_pb2.py +0 -28
  217. flyte/_protos/common/runtime_version_pb2.pyi +0 -24
  218. flyte/_protos/common/runtime_version_pb2_grpc.py +0 -4
  219. flyte/_protos/logs/dataplane/payload_pb2.py +0 -96
  220. flyte/_protos/logs/dataplane/payload_pb2.pyi +0 -168
  221. flyte/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
  222. flyte/_protos/secret/definition_pb2.py +0 -49
  223. flyte/_protos/secret/definition_pb2.pyi +0 -93
  224. flyte/_protos/secret/definition_pb2_grpc.py +0 -4
  225. flyte/_protos/secret/payload_pb2.py +0 -62
  226. flyte/_protos/secret/payload_pb2.pyi +0 -94
  227. flyte/_protos/secret/payload_pb2_grpc.py +0 -4
  228. flyte/_protos/secret/secret_pb2.py +0 -38
  229. flyte/_protos/secret/secret_pb2.pyi +0 -6
  230. flyte/_protos/secret/secret_pb2_grpc.py +0 -198
  231. flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
  232. flyte/_protos/validate/validate/validate_pb2.py +0 -76
  233. flyte/_protos/workflow/node_execution_service_pb2.py +0 -26
  234. flyte/_protos/workflow/node_execution_service_pb2.pyi +0 -4
  235. flyte/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
  236. flyte/_protos/workflow/queue_service_pb2.py +0 -106
  237. flyte/_protos/workflow/queue_service_pb2.pyi +0 -141
  238. flyte/_protos/workflow/queue_service_pb2_grpc.py +0 -172
  239. flyte/_protos/workflow/run_definition_pb2.py +0 -128
  240. flyte/_protos/workflow/run_definition_pb2.pyi +0 -310
  241. flyte/_protos/workflow/run_definition_pb2_grpc.py +0 -4
  242. flyte/_protos/workflow/run_logs_service_pb2.py +0 -41
  243. flyte/_protos/workflow/run_logs_service_pb2.pyi +0 -28
  244. flyte/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
  245. flyte/_protos/workflow/run_service_pb2.py +0 -133
  246. flyte/_protos/workflow/run_service_pb2.pyi +0 -175
  247. flyte/_protos/workflow/run_service_pb2_grpc.py +0 -412
  248. flyte/_protos/workflow/state_service_pb2.py +0 -58
  249. flyte/_protos/workflow/state_service_pb2.pyi +0 -71
  250. flyte/_protos/workflow/state_service_pb2_grpc.py +0 -138
  251. flyte/_protos/workflow/task_definition_pb2.py +0 -72
  252. flyte/_protos/workflow/task_definition_pb2.pyi +0 -65
  253. flyte/_protos/workflow/task_definition_pb2_grpc.py +0 -4
  254. flyte/_protos/workflow/task_service_pb2.py +0 -44
  255. flyte/_protos/workflow/task_service_pb2.pyi +0 -31
  256. flyte/_protos/workflow/task_service_pb2_grpc.py +0 -104
  257. flyte/io/_dataframe.py +0 -0
  258. flyte/io/pickle/__init__.py +0 -0
  259. flyte/remote/_console.py +0 -18
  260. flyte-0.2.0b1.dist-info/METADATA +0 -179
  261. flyte-0.2.0b1.dist-info/RECORD +0 -204
  262. flyte-0.2.0b1.dist-info/entry_points.txt +0 -3
  263. /flyte/{_cli → _debug}/__init__.py +0 -0
  264. /flyte/{_protos → _keyring}/__init__.py +0 -0
  265. {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/WHEEL +0 -0
  266. {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,383 @@
1
+ """
2
+ Serialization module for AppEnvironment to AppIDL conversion.
3
+
4
+ This module provides functionality to serialize an AppEnvironment object into
5
+ the AppIDL protobuf format, using SerializationContext for configuration.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from copy import deepcopy
11
+ from dataclasses import replace
12
+ from typing import List, Optional, Union
13
+
14
+ from flyteidl2.app import app_definition_pb2
15
+ from flyteidl2.common import runtime_version_pb2
16
+ from flyteidl2.core import literals_pb2, tasks_pb2
17
+ from google.protobuf.duration_pb2 import Duration
18
+
19
+ import flyte
20
+ import flyte.io
21
+ from flyte._internal.runtime.resources_serde import get_proto_extended_resources, get_proto_resources
22
+ from flyte._internal.runtime.task_serde import get_security_context, lookup_image_in_cache
23
+ from flyte._logging import logger
24
+ from flyte.app import AppEnvironment, Parameter, Scaling
25
+ from flyte.app._parameter import _DelayedValue
26
+ from flyte.models import SerializationContext
27
+ from flyte.syncify import syncify
28
+
29
+
30
+ def get_proto_container(
31
+ app_env: AppEnvironment,
32
+ serialization_context: SerializationContext,
33
+ parameter_overrides: list[Parameter] | None = None,
34
+ ) -> tasks_pb2.Container:
35
+ """
36
+ Construct the container specification.
37
+
38
+ Args:
39
+ app_env: The app environment
40
+ serialization_context: Serialization context
41
+ parameter_overrides: Parameter overrides to apply to the app environment.
42
+ Returns:
43
+ Container protobuf message
44
+ """
45
+ from flyte import Image
46
+
47
+ env = [literals_pb2.KeyValuePair(key=k, value=v) for k, v in app_env.env_vars.items()] if app_env.env_vars else None
48
+ resources = get_proto_resources(app_env.resources)
49
+
50
+ if app_env.image == "auto":
51
+ img = Image.from_debian_base()
52
+ elif isinstance(app_env.image, str):
53
+ img = Image.from_base(app_env.image)
54
+ else:
55
+ img = app_env.image
56
+
57
+ env_name = app_env.name
58
+ img_uri = lookup_image_in_cache(serialization_context, env_name, img)
59
+
60
+ p = app_env.get_port()
61
+ container_ports = [tasks_pb2.ContainerPort(container_port=p.port, name=p.name)]
62
+
63
+ return tasks_pb2.Container(
64
+ image=img_uri,
65
+ command=app_env.container_cmd(serialization_context, parameter_overrides),
66
+ args=app_env.container_args(serialization_context),
67
+ resources=resources,
68
+ ports=container_ports,
69
+ env=env,
70
+ )
71
+
72
+
73
+ def _sanitize_resource_name(resource: tasks_pb2.Resources.ResourceEntry) -> str:
74
+ """
75
+ Sanitize resource name for Kubernetes compatibility.
76
+
77
+ Args:
78
+ resource: Resource entry
79
+
80
+ Returns:
81
+ Sanitized resource name
82
+ """
83
+ return tasks_pb2.Resources.ResourceName.Name(resource.name).lower().replace("_", "-")
84
+
85
+
86
+ def _serialized_pod_spec(
87
+ app_env: AppEnvironment,
88
+ pod_template: flyte.PodTemplate,
89
+ serialization_context: SerializationContext,
90
+ ) -> dict:
91
+ """
92
+ Convert pod spec into a dict for serialization.
93
+
94
+ Args:
95
+ app_env: The app environment
96
+ pod_template: Pod template specification
97
+ serialization_context: Serialization context
98
+
99
+ Returns:
100
+ Dictionary representation of the pod spec
101
+ """
102
+ from kubernetes.client import ApiClient
103
+ from kubernetes.client.models import V1Container, V1ContainerPort, V1EnvVar, V1ResourceRequirements
104
+
105
+ pod_template = deepcopy(pod_template)
106
+
107
+ if pod_template.pod_spec is None:
108
+ return {}
109
+
110
+ if pod_template.primary_container_name != "app":
111
+ msg = "Primary container name must be 'app'"
112
+ raise ValueError(msg)
113
+
114
+ containers: list[V1Container] = pod_template.pod_spec.containers
115
+ primary_exists = any(container.name == pod_template.primary_container_name for container in containers)
116
+
117
+ if not primary_exists:
118
+ msg = "Primary container does not exist with name 'app'"
119
+ raise ValueError(msg)
120
+
121
+ final_containers = []
122
+
123
+ # Process containers
124
+ for container in containers:
125
+ img = container.image
126
+ if isinstance(img, flyte.Image):
127
+ img = lookup_image_in_cache(serialization_context, container.name, img)
128
+ container.image = img
129
+
130
+ if container.name == pod_template.primary_container_name:
131
+ container.args = app_env.container_args(serialization_context)
132
+ container.command = app_env.container_cmd(serialization_context)
133
+
134
+ limits, requests = {}, {}
135
+ resources = get_proto_resources(app_env.resources)
136
+ if resources:
137
+ for resource in resources.limits:
138
+ limits[_sanitize_resource_name(resource)] = resource.value
139
+ for resource in resources.requests:
140
+ requests[_sanitize_resource_name(resource)] = resource.value
141
+
142
+ resource_requirements = V1ResourceRequirements(limits=limits, requests=requests)
143
+
144
+ if limits or requests:
145
+ container.resources = resource_requirements
146
+
147
+ if app_env.env_vars:
148
+ container.env = [V1EnvVar(name=k, value=v) for k, v in app_env.env_vars.items()] + (container.env or [])
149
+
150
+ _port = app_env.get_port()
151
+ container.ports = [V1ContainerPort(container_port=_port.port, name=_port.name)] + (container.ports or [])
152
+
153
+ final_containers.append(container)
154
+
155
+ pod_template.pod_spec.containers = final_containers
156
+ return ApiClient().sanitize_for_serialization(pod_template.pod_spec)
157
+
158
+
159
+ def _get_k8s_pod(
160
+ app_env: AppEnvironment,
161
+ pod_template: flyte.PodTemplate,
162
+ serialization_context: SerializationContext,
163
+ ) -> tasks_pb2.K8sPod:
164
+ """
165
+ Convert pod_template into a K8sPod IDL.
166
+
167
+ Args:
168
+ app_env: The app environment
169
+ pod_template: Pod template specification
170
+ serialization_context: Serialization context
171
+
172
+ Returns:
173
+ K8sPod protobuf message
174
+ """
175
+ import json
176
+
177
+ from google.protobuf.json_format import Parse
178
+ from google.protobuf.struct_pb2 import Struct
179
+
180
+ pod_spec_dict = _serialized_pod_spec(app_env, pod_template, serialization_context)
181
+ pod_spec_idl = Parse(json.dumps(pod_spec_dict), Struct())
182
+
183
+ metadata = tasks_pb2.K8sObjectMetadata(
184
+ labels=pod_template.labels,
185
+ annotations=pod_template.annotations,
186
+ )
187
+ return tasks_pb2.K8sPod(pod_spec=pod_spec_idl, metadata=metadata)
188
+
189
+
190
+ def _get_scaling_metric(
191
+ metric: Optional[Union[Scaling.Concurrency, Scaling.RequestRate]],
192
+ ) -> Optional[app_definition_pb2.ScalingMetric]:
193
+ """
194
+ Convert scaling metric to protobuf format.
195
+
196
+ Args:
197
+ metric: Scaling metric (Concurrency or RequestRate)
198
+
199
+ Returns:
200
+ ScalingMetric protobuf message or None
201
+ """
202
+
203
+ if metric is None:
204
+ return None
205
+
206
+ if isinstance(metric, Scaling.Concurrency):
207
+ return app_definition_pb2.ScalingMetric(concurrency=app_definition_pb2.Concurrency(val=metric.val))
208
+ elif isinstance(metric, Scaling.RequestRate):
209
+ return app_definition_pb2.ScalingMetric(request_rate=app_definition_pb2.RequestRate(val=metric.val))
210
+
211
+ return None
212
+
213
+
214
+ async def _materialize_parameters_with_delayed_values(parameters: List[Parameter]) -> List[Parameter]:
215
+ """
216
+ Materialize the parameters that contain delayed values. This is important for both
217
+ serializing the parameter for the container command and for the app idl parameters collection.
218
+
219
+ Args:
220
+ parameters: The parameters to materialize.
221
+
222
+ Returns:
223
+ The materialized parameters.
224
+ """
225
+ _parameters = []
226
+ for param in parameters:
227
+ if isinstance(param.value, _DelayedValue):
228
+ logger.info(f"Materializing {param.name} with delayed values of type {param.value.type}")
229
+ value = await param.value.get()
230
+ assert isinstance(value, (str, flyte.io.File, flyte.io.Dir)), (
231
+ f"Materialized value must be a string, file or directory, found {type(value)}"
232
+ )
233
+ _parameters.append(replace(param, value=await param.value.get()))
234
+ else:
235
+ _parameters.append(param)
236
+ return _parameters
237
+
238
+
239
+ async def translate_parameters(parameters: List[Parameter]) -> app_definition_pb2.InputList:
240
+ """
241
+ Translate parameters to protobuf format.
242
+
243
+ Returns:
244
+ InputList protobuf message
245
+ """
246
+ if not parameters:
247
+ return app_definition_pb2.InputList()
248
+
249
+ parameters_list = []
250
+ for param in parameters:
251
+ if isinstance(param.value, str):
252
+ parameters_list.append(app_definition_pb2.Input(name=param.name, string_value=param.value))
253
+ elif isinstance(param.value, flyte.io.File):
254
+ parameters_list.append(app_definition_pb2.Input(name=param.name, string_value=str(param.value.path)))
255
+ elif isinstance(param.value, flyte.io.Dir):
256
+ parameters_list.append(app_definition_pb2.Input(name=param.name, string_value=str(param.value.path)))
257
+ else:
258
+ raise ValueError(f"Unsupported parameter value type: {type(param.value)}")
259
+ return app_definition_pb2.InputList(items=parameters_list)
260
+
261
+
262
+ @syncify
263
+ async def translate_app_env_to_idl(
264
+ app_env: AppEnvironment,
265
+ serialization_context: SerializationContext,
266
+ parameter_overrides: list[Parameter] | None = None,
267
+ desired_state: app_definition_pb2.Spec.DesiredState = app_definition_pb2.Spec.DesiredState.DESIRED_STATE_ACTIVE,
268
+ ) -> app_definition_pb2.App:
269
+ """
270
+ Translate an AppEnvironment to AppIDL protobuf format.
271
+
272
+ This is the main entry point for serializing an AppEnvironment object into
273
+ the AppIDL protobuf format.
274
+
275
+ Args:
276
+ app_env: The app environment to serialize
277
+ serialization_context: Serialization context containing org, project, domain, version, etc.
278
+ parameter_overrides: Parameter overrides to apply to the app environment.
279
+ desired_state: Desired state of the app (ACTIVE, INACTIVE, etc.)
280
+
281
+ Returns:
282
+ AppIDL protobuf message
283
+ """
284
+ # Build security context
285
+ task_sec_ctx = get_security_context(app_env.secrets)
286
+ allow_anonymous = False
287
+ if not app_env.requires_auth:
288
+ allow_anonymous = True
289
+
290
+ security_context = None
291
+ if task_sec_ctx or allow_anonymous:
292
+ security_context = app_definition_pb2.SecurityContext(
293
+ run_as=task_sec_ctx.run_as if task_sec_ctx else None,
294
+ secrets=task_sec_ctx.secrets if task_sec_ctx else [],
295
+ allow_anonymous=allow_anonymous,
296
+ )
297
+
298
+ # Build autoscaling config
299
+ scaling_metric = _get_scaling_metric(app_env.scaling.metric)
300
+
301
+ dur = None
302
+ if app_env.scaling.scaledown_after:
303
+ dur = Duration()
304
+ dur.FromTimedelta(app_env.scaling.scaledown_after)
305
+
306
+ min_replicas, max_replicas = app_env.scaling.get_replicas()
307
+ autoscaling = app_definition_pb2.AutoscalingConfig(
308
+ replicas=app_definition_pb2.Replicas(min=min_replicas, max=max_replicas),
309
+ scaledown_period=dur,
310
+ scaling_metric=scaling_metric,
311
+ )
312
+
313
+ # Build spec based on image type
314
+ parameters = await _materialize_parameters_with_delayed_values(parameter_overrides or app_env.parameters)
315
+ container = None
316
+ pod = None
317
+ if app_env.pod_template:
318
+ if isinstance(app_env.pod_template, str):
319
+ raise NotImplementedError("PodTemplate as str is not supported yet")
320
+ pod = _get_k8s_pod(
321
+ app_env,
322
+ app_env.pod_template,
323
+ serialization_context,
324
+ )
325
+ elif app_env.image:
326
+ container = get_proto_container(
327
+ app_env,
328
+ serialization_context,
329
+ parameter_overrides=parameters,
330
+ )
331
+ else:
332
+ msg = "image must be a str, Image, or PodTemplate"
333
+ raise ValueError(msg)
334
+
335
+ ingress = app_definition_pb2.IngressConfig(
336
+ private=False,
337
+ subdomain=app_env.domain.subdomain if app_env.domain else None,
338
+ cname=app_env.domain.custom_domain if app_env.domain else None,
339
+ )
340
+
341
+ # Build links
342
+ links = None
343
+ if app_env.links:
344
+ links = [
345
+ app_definition_pb2.Link(path=link.path, title=link.title, is_relative=link.is_relative)
346
+ for link in app_env.links
347
+ ]
348
+
349
+ # Build profile
350
+ profile = app_definition_pb2.Profile(
351
+ type=app_env.type,
352
+ short_description=app_env.description,
353
+ )
354
+
355
+ # Build the full App IDL
356
+ return app_definition_pb2.App(
357
+ metadata=app_definition_pb2.Meta(
358
+ id=app_definition_pb2.Identifier(
359
+ org=serialization_context.org,
360
+ project=serialization_context.project,
361
+ domain=serialization_context.domain,
362
+ name=app_env.name,
363
+ ),
364
+ ),
365
+ spec=app_definition_pb2.Spec(
366
+ desired_state=desired_state,
367
+ ingress=ingress,
368
+ autoscaling=autoscaling,
369
+ security_context=security_context,
370
+ cluster_pool=app_env.cluster_pool,
371
+ extended_resources=get_proto_extended_resources(app_env.resources),
372
+ runtime_metadata=runtime_version_pb2.RuntimeMetadata(
373
+ type=runtime_version_pb2.RuntimeMetadata.RuntimeType.FLYTE_SDK,
374
+ version=flyte.version(),
375
+ flavor="python",
376
+ ),
377
+ profile=profile,
378
+ links=links,
379
+ container=container,
380
+ pod=pod,
381
+ inputs=await translate_parameters(parameters),
382
+ ),
383
+ )
flyte/app/_types.py ADDED
@@ -0,0 +1,113 @@
1
+ from dataclasses import dataclass
2
+ from datetime import timedelta
3
+ from typing import Optional, Tuple, Union
4
+
5
+ import rich.repr
6
+
7
+ INVALID_APP_PORTS = [8012, 8022, 8112, 9090, 9091]
8
+
9
+
10
+ @rich.repr.auto
11
+ @dataclass(frozen=True)
12
+ class Port:
13
+ port: int
14
+ name: Optional[str] = None
15
+
16
+ def __post_init__(self):
17
+ if self.port in INVALID_APP_PORTS:
18
+ invalid_ports = ", ".join(str(p) for p in INVALID_APP_PORTS)
19
+ msg = f"port {self.port} is not allowed. Please do not use ports: {invalid_ports}"
20
+ raise ValueError(msg)
21
+
22
+
23
+ @rich.repr.auto
24
+ @dataclass(frozen=True)
25
+ class Link:
26
+ """Custom links to add to the app"""
27
+
28
+ path: str
29
+ title: str
30
+ is_relative: bool = False
31
+
32
+
33
+ @rich.repr.auto
34
+ @dataclass
35
+ class Scaling:
36
+ @dataclass(frozen=True)
37
+ class Concurrency:
38
+ """
39
+ Use this to specify the concurrency metric for autoscaling, i.e. the number of concurrent requests at a replica
40
+ at which to scale up.
41
+ """
42
+
43
+ val: int
44
+
45
+ def __post_init__(self):
46
+ if self.val < 1:
47
+ raise ValueError("Concurrency must be greater than or equal to 1")
48
+
49
+ @dataclass
50
+ class RequestRate:
51
+ """
52
+ Use this to specify the request rate metric for autoscaling, i.e. the number of requests per second at a replica
53
+ at which to scale up.
54
+ """
55
+
56
+ val: int
57
+
58
+ def __post_init__(self):
59
+ if self.val < 1:
60
+ raise ValueError("Request rate must be greater than or equal to 1")
61
+
62
+ """Number of replicas to run. Can be a single int or a tuple of two ints representing the min and max replicas."""
63
+ replicas: Union[int, Tuple[int, int]] = (0, 1)
64
+
65
+ """Metric to use for autoscaling. Can be a concurrency or request rate."""
66
+ metric: Optional[Union[Concurrency, RequestRate]] = None
67
+
68
+ """Time to wait after the last request before scaling down. Can be a number of seconds or a timedelta."""
69
+ scaledown_after: int | timedelta | None = None
70
+
71
+ def __post_init__(self):
72
+ if isinstance(self.replicas, int):
73
+ if self.replicas < 0:
74
+ raise ValueError("replicas must be greater than or equal to 0")
75
+ self.replicas = (self.replicas, self.replicas)
76
+ elif isinstance(self.replicas, tuple):
77
+ if len(self.replicas) != 2:
78
+ raise ValueError("replicas tuple must be of length 2")
79
+ min_replicas, max_replicas = self.replicas
80
+ if min_replicas < 0:
81
+ raise ValueError("min_replicas must be greater than or equal to 0")
82
+ if max_replicas < 1 or max_replicas < min_replicas:
83
+ raise ValueError("max_replicas must be greater than or equal to 1 and min_replicas")
84
+ else:
85
+ raise TypeError("replicas must be an int or a tuple of two ints")
86
+
87
+ if self.metric:
88
+ if not isinstance(self.metric, (Scaling.Concurrency, Scaling.RequestRate)):
89
+ raise TypeError("metric must be an instance of Scaling.Concurrency or Scaling.RequestRate")
90
+
91
+ if self.scaledown_after:
92
+ if isinstance(self.scaledown_after, int):
93
+ self.scaledown_after = timedelta(seconds=self.scaledown_after)
94
+ elif not isinstance(self.scaledown_after, timedelta):
95
+ raise TypeError("scaledown_after must be an int or a timedelta")
96
+
97
+ def get_replicas(self) -> Tuple[int, int]:
98
+ if isinstance(self.replicas, int):
99
+ return self.replicas, self.replicas
100
+ return self.replicas
101
+
102
+
103
+ @rich.repr.auto
104
+ @dataclass
105
+ class Domain:
106
+ # SubDomain config
107
+
108
+ """Subdomain to use for the domain. If not set, the default subdomain will be used."""
109
+
110
+ subdomain: Optional[str] = None
111
+
112
+ """Custom domain to use for the domain. If not set, the default custom domain will be used."""
113
+ custom_domain: Optional[str] = None
@@ -0,0 +1,9 @@
1
+ from ._auth_middleware import (
2
+ FastAPIPassthroughAuthMiddleware,
3
+ )
4
+ from ._fastapi import FastAPIAppEnvironment
5
+
6
+ __all__ = [
7
+ "FastAPIAppEnvironment",
8
+ "FastAPIPassthroughAuthMiddleware",
9
+ ]