flyte 0.0.1b3__py3-none-any.whl → 0.2.0a0__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 (319) hide show
  1. flyte/__init__.py +20 -4
  2. flyte/_bin/runtime.py +33 -7
  3. flyte/_build.py +3 -2
  4. flyte/_cache/cache.py +1 -2
  5. flyte/_code_bundle/_packaging.py +1 -1
  6. flyte/_code_bundle/_utils.py +0 -16
  7. flyte/_code_bundle/bundle.py +43 -12
  8. flyte/_context.py +8 -2
  9. flyte/_deploy.py +56 -15
  10. flyte/_environment.py +45 -4
  11. flyte/_excepthook.py +37 -0
  12. flyte/_group.py +2 -1
  13. flyte/_image.py +8 -4
  14. flyte/_initialize.py +112 -254
  15. flyte/_interface.py +3 -3
  16. flyte/_internal/controllers/__init__.py +19 -6
  17. flyte/_internal/controllers/_local_controller.py +83 -8
  18. flyte/_internal/controllers/_trace.py +2 -1
  19. flyte/_internal/controllers/remote/__init__.py +27 -7
  20. flyte/_internal/controllers/remote/_action.py +7 -2
  21. flyte/_internal/controllers/remote/_client.py +5 -1
  22. flyte/_internal/controllers/remote/_controller.py +159 -26
  23. flyte/_internal/controllers/remote/_core.py +13 -5
  24. flyte/_internal/controllers/remote/_informer.py +4 -4
  25. flyte/_internal/controllers/remote/_service_protocol.py +6 -6
  26. flyte/_internal/imagebuild/docker_builder.py +12 -1
  27. flyte/_internal/imagebuild/image_builder.py +16 -11
  28. flyte/_internal/runtime/convert.py +164 -21
  29. flyte/_internal/runtime/entrypoints.py +1 -1
  30. flyte/_internal/runtime/io.py +3 -3
  31. flyte/_internal/runtime/task_serde.py +140 -20
  32. flyte/_internal/runtime/taskrunner.py +4 -3
  33. flyte/_internal/runtime/types_serde.py +1 -1
  34. flyte/_logging.py +12 -1
  35. flyte/_map.py +215 -0
  36. flyte/_pod.py +19 -0
  37. flyte/_protos/common/list_pb2.py +3 -3
  38. flyte/_protos/common/list_pb2.pyi +2 -0
  39. flyte/_protos/logs/dataplane/payload_pb2.py +28 -24
  40. flyte/_protos/logs/dataplane/payload_pb2.pyi +11 -2
  41. flyte/_protos/workflow/common_pb2.py +27 -0
  42. flyte/_protos/workflow/common_pb2.pyi +14 -0
  43. flyte/_protos/workflow/environment_pb2.py +29 -0
  44. flyte/_protos/workflow/environment_pb2.pyi +12 -0
  45. flyte/_protos/workflow/queue_service_pb2.py +40 -41
  46. flyte/_protos/workflow/queue_service_pb2.pyi +35 -30
  47. flyte/_protos/workflow/queue_service_pb2_grpc.py +15 -15
  48. flyte/_protos/workflow/run_definition_pb2.py +61 -61
  49. flyte/_protos/workflow/run_definition_pb2.pyi +8 -4
  50. flyte/_protos/workflow/run_service_pb2.py +20 -24
  51. flyte/_protos/workflow/run_service_pb2.pyi +2 -6
  52. flyte/_protos/workflow/state_service_pb2.py +36 -28
  53. flyte/_protos/workflow/state_service_pb2.pyi +19 -15
  54. flyte/_protos/workflow/state_service_pb2_grpc.py +28 -28
  55. flyte/_protos/workflow/task_definition_pb2.py +29 -22
  56. flyte/_protos/workflow/task_definition_pb2.pyi +21 -5
  57. flyte/_protos/workflow/task_service_pb2.py +27 -11
  58. flyte/_protos/workflow/task_service_pb2.pyi +29 -1
  59. flyte/_protos/workflow/task_service_pb2_grpc.py +34 -0
  60. flyte/_run.py +166 -95
  61. flyte/_task.py +110 -28
  62. flyte/_task_environment.py +55 -72
  63. flyte/_trace.py +6 -14
  64. flyte/_utils/__init__.py +6 -0
  65. flyte/_utils/async_cache.py +139 -0
  66. flyte/_utils/coro_management.py +0 -2
  67. flyte/_utils/helpers.py +45 -19
  68. flyte/_utils/org_discovery.py +57 -0
  69. flyte/_version.py +2 -2
  70. flyte/cli/__init__.py +3 -0
  71. flyte/cli/_abort.py +28 -0
  72. flyte/{_cli → cli}/_common.py +73 -23
  73. flyte/cli/_create.py +145 -0
  74. flyte/{_cli → cli}/_delete.py +4 -4
  75. flyte/{_cli → cli}/_deploy.py +26 -14
  76. flyte/cli/_gen.py +163 -0
  77. flyte/{_cli → cli}/_get.py +98 -23
  78. {union/_cli → flyte/cli}/_params.py +106 -147
  79. flyte/{_cli → cli}/_run.py +99 -20
  80. flyte/cli/main.py +166 -0
  81. flyte/config/__init__.py +3 -0
  82. flyte/config/_config.py +216 -0
  83. flyte/config/_internal.py +64 -0
  84. flyte/config/_reader.py +207 -0
  85. flyte/errors.py +29 -0
  86. flyte/extras/_container.py +33 -43
  87. flyte/io/__init__.py +17 -1
  88. flyte/io/_dir.py +2 -2
  89. flyte/io/_file.py +3 -4
  90. flyte/io/{structured_dataset → _structured_dataset}/basic_dfs.py +1 -1
  91. flyte/io/{structured_dataset → _structured_dataset}/structured_dataset.py +1 -1
  92. flyte/{_datastructures.py → models.py} +56 -7
  93. flyte/remote/__init__.py +2 -1
  94. flyte/remote/_client/_protocols.py +2 -0
  95. flyte/remote/_client/auth/_auth_utils.py +14 -0
  96. flyte/remote/_client/auth/_channel.py +34 -3
  97. flyte/remote/_client/auth/_token_client.py +3 -3
  98. flyte/remote/_client/controlplane.py +13 -13
  99. flyte/remote/_console.py +1 -1
  100. flyte/remote/_data.py +10 -6
  101. flyte/remote/_logs.py +89 -29
  102. flyte/remote/_project.py +8 -9
  103. flyte/remote/_run.py +228 -131
  104. flyte/remote/_secret.py +12 -12
  105. flyte/remote/_task.py +179 -15
  106. flyte/report/_report.py +4 -4
  107. flyte/storage/__init__.py +5 -0
  108. flyte/storage/_config.py +233 -0
  109. flyte/storage/_storage.py +23 -3
  110. flyte/syncify/__init__.py +56 -0
  111. flyte/syncify/_api.py +371 -0
  112. flyte/types/__init__.py +23 -0
  113. flyte/types/_interface.py +22 -7
  114. flyte/{io/pickle/transformer.py → types/_pickle.py} +2 -1
  115. flyte/types/_type_engine.py +95 -18
  116. flyte-0.2.0a0.dist-info/METADATA +249 -0
  117. flyte-0.2.0a0.dist-info/RECORD +218 -0
  118. {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/entry_points.txt +1 -1
  119. flyte/_api_commons.py +0 -3
  120. flyte/_cli/__init__.py +0 -0
  121. flyte/_cli/_create.py +0 -42
  122. flyte/_cli/main.py +0 -72
  123. flyte/_internal/controllers/pbhash.py +0 -39
  124. flyte/io/_dataframe.py +0 -0
  125. flyte/io/pickle/__init__.py +0 -0
  126. flyte-0.0.1b3.dist-info/METADATA +0 -179
  127. flyte-0.0.1b3.dist-info/RECORD +0 -390
  128. union/__init__.py +0 -54
  129. union/_api_commons.py +0 -3
  130. union/_bin/__init__.py +0 -0
  131. union/_bin/runtime.py +0 -113
  132. union/_build.py +0 -25
  133. union/_cache/__init__.py +0 -12
  134. union/_cache/cache.py +0 -141
  135. union/_cache/defaults.py +0 -9
  136. union/_cache/policy_function_body.py +0 -42
  137. union/_cli/__init__.py +0 -0
  138. union/_cli/_common.py +0 -263
  139. union/_cli/_create.py +0 -40
  140. union/_cli/_delete.py +0 -23
  141. union/_cli/_deploy.py +0 -120
  142. union/_cli/_get.py +0 -162
  143. union/_cli/_run.py +0 -150
  144. union/_cli/main.py +0 -72
  145. union/_code_bundle/__init__.py +0 -8
  146. union/_code_bundle/_ignore.py +0 -113
  147. union/_code_bundle/_packaging.py +0 -187
  148. union/_code_bundle/_utils.py +0 -342
  149. union/_code_bundle/bundle.py +0 -176
  150. union/_context.py +0 -146
  151. union/_datastructures.py +0 -295
  152. union/_deploy.py +0 -185
  153. union/_doc.py +0 -29
  154. union/_docstring.py +0 -26
  155. union/_environment.py +0 -43
  156. union/_group.py +0 -31
  157. union/_hash.py +0 -23
  158. union/_image.py +0 -760
  159. union/_initialize.py +0 -585
  160. union/_interface.py +0 -84
  161. union/_internal/__init__.py +0 -3
  162. union/_internal/controllers/__init__.py +0 -77
  163. union/_internal/controllers/_local_controller.py +0 -77
  164. union/_internal/controllers/pbhash.py +0 -39
  165. union/_internal/controllers/remote/__init__.py +0 -40
  166. union/_internal/controllers/remote/_action.py +0 -131
  167. union/_internal/controllers/remote/_client.py +0 -43
  168. union/_internal/controllers/remote/_controller.py +0 -169
  169. union/_internal/controllers/remote/_core.py +0 -341
  170. union/_internal/controllers/remote/_informer.py +0 -260
  171. union/_internal/controllers/remote/_service_protocol.py +0 -44
  172. union/_internal/imagebuild/__init__.py +0 -11
  173. union/_internal/imagebuild/docker_builder.py +0 -416
  174. union/_internal/imagebuild/image_builder.py +0 -243
  175. union/_internal/imagebuild/remote_builder.py +0 -0
  176. union/_internal/resolvers/__init__.py +0 -0
  177. union/_internal/resolvers/_task_module.py +0 -31
  178. union/_internal/resolvers/common.py +0 -24
  179. union/_internal/resolvers/default.py +0 -27
  180. union/_internal/runtime/__init__.py +0 -0
  181. union/_internal/runtime/convert.py +0 -163
  182. union/_internal/runtime/entrypoints.py +0 -121
  183. union/_internal/runtime/io.py +0 -136
  184. union/_internal/runtime/resources_serde.py +0 -134
  185. union/_internal/runtime/task_serde.py +0 -202
  186. union/_internal/runtime/taskrunner.py +0 -179
  187. union/_internal/runtime/types_serde.py +0 -53
  188. union/_logging.py +0 -124
  189. union/_protos/__init__.py +0 -0
  190. union/_protos/common/authorization_pb2.py +0 -66
  191. union/_protos/common/authorization_pb2.pyi +0 -106
  192. union/_protos/common/identifier_pb2.py +0 -71
  193. union/_protos/common/identifier_pb2.pyi +0 -82
  194. union/_protos/common/identity_pb2.py +0 -48
  195. union/_protos/common/identity_pb2.pyi +0 -72
  196. union/_protos/common/identity_pb2_grpc.py +0 -4
  197. union/_protos/common/list_pb2.py +0 -36
  198. union/_protos/common/list_pb2.pyi +0 -69
  199. union/_protos/common/list_pb2_grpc.py +0 -4
  200. union/_protos/common/policy_pb2.py +0 -37
  201. union/_protos/common/policy_pb2.pyi +0 -27
  202. union/_protos/common/policy_pb2_grpc.py +0 -4
  203. union/_protos/common/role_pb2.py +0 -37
  204. union/_protos/common/role_pb2.pyi +0 -51
  205. union/_protos/common/role_pb2_grpc.py +0 -4
  206. union/_protos/common/runtime_version_pb2.py +0 -28
  207. union/_protos/common/runtime_version_pb2.pyi +0 -24
  208. union/_protos/common/runtime_version_pb2_grpc.py +0 -4
  209. union/_protos/logs/dataplane/payload_pb2.py +0 -96
  210. union/_protos/logs/dataplane/payload_pb2.pyi +0 -168
  211. union/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
  212. union/_protos/secret/definition_pb2.py +0 -49
  213. union/_protos/secret/definition_pb2.pyi +0 -93
  214. union/_protos/secret/definition_pb2_grpc.py +0 -4
  215. union/_protos/secret/payload_pb2.py +0 -62
  216. union/_protos/secret/payload_pb2.pyi +0 -94
  217. union/_protos/secret/payload_pb2_grpc.py +0 -4
  218. union/_protos/secret/secret_pb2.py +0 -38
  219. union/_protos/secret/secret_pb2.pyi +0 -6
  220. union/_protos/secret/secret_pb2_grpc.py +0 -198
  221. union/_protos/validate/validate/validate_pb2.py +0 -76
  222. union/_protos/workflow/node_execution_service_pb2.py +0 -26
  223. union/_protos/workflow/node_execution_service_pb2.pyi +0 -4
  224. union/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
  225. union/_protos/workflow/queue_service_pb2.py +0 -75
  226. union/_protos/workflow/queue_service_pb2.pyi +0 -103
  227. union/_protos/workflow/queue_service_pb2_grpc.py +0 -172
  228. union/_protos/workflow/run_definition_pb2.py +0 -100
  229. union/_protos/workflow/run_definition_pb2.pyi +0 -256
  230. union/_protos/workflow/run_definition_pb2_grpc.py +0 -4
  231. union/_protos/workflow/run_logs_service_pb2.py +0 -41
  232. union/_protos/workflow/run_logs_service_pb2.pyi +0 -28
  233. union/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
  234. union/_protos/workflow/run_service_pb2.py +0 -133
  235. union/_protos/workflow/run_service_pb2.pyi +0 -173
  236. union/_protos/workflow/run_service_pb2_grpc.py +0 -412
  237. union/_protos/workflow/state_service_pb2.py +0 -58
  238. union/_protos/workflow/state_service_pb2.pyi +0 -69
  239. union/_protos/workflow/state_service_pb2_grpc.py +0 -138
  240. union/_protos/workflow/task_definition_pb2.py +0 -72
  241. union/_protos/workflow/task_definition_pb2.pyi +0 -65
  242. union/_protos/workflow/task_definition_pb2_grpc.py +0 -4
  243. union/_protos/workflow/task_service_pb2.py +0 -44
  244. union/_protos/workflow/task_service_pb2.pyi +0 -31
  245. union/_protos/workflow/task_service_pb2_grpc.py +0 -104
  246. union/_resources.py +0 -226
  247. union/_retry.py +0 -32
  248. union/_reusable_environment.py +0 -25
  249. union/_run.py +0 -374
  250. union/_secret.py +0 -61
  251. union/_task.py +0 -354
  252. union/_task_environment.py +0 -186
  253. union/_timeout.py +0 -47
  254. union/_tools.py +0 -27
  255. union/_utils/__init__.py +0 -11
  256. union/_utils/asyn.py +0 -119
  257. union/_utils/file_handling.py +0 -71
  258. union/_utils/helpers.py +0 -46
  259. union/_utils/lazy_module.py +0 -54
  260. union/_utils/uv_script_parser.py +0 -49
  261. union/_version.py +0 -21
  262. union/connectors/__init__.py +0 -0
  263. union/errors.py +0 -128
  264. union/extras/__init__.py +0 -5
  265. union/extras/_container.py +0 -263
  266. union/io/__init__.py +0 -11
  267. union/io/_dataframe.py +0 -0
  268. union/io/_dir.py +0 -425
  269. union/io/_file.py +0 -418
  270. union/io/pickle/__init__.py +0 -0
  271. union/io/pickle/transformer.py +0 -117
  272. union/io/structured_dataset/__init__.py +0 -122
  273. union/io/structured_dataset/basic_dfs.py +0 -219
  274. union/io/structured_dataset/structured_dataset.py +0 -1057
  275. union/py.typed +0 -0
  276. union/remote/__init__.py +0 -23
  277. union/remote/_client/__init__.py +0 -0
  278. union/remote/_client/_protocols.py +0 -129
  279. union/remote/_client/auth/__init__.py +0 -12
  280. union/remote/_client/auth/_authenticators/__init__.py +0 -0
  281. union/remote/_client/auth/_authenticators/base.py +0 -391
  282. union/remote/_client/auth/_authenticators/client_credentials.py +0 -73
  283. union/remote/_client/auth/_authenticators/device_code.py +0 -120
  284. union/remote/_client/auth/_authenticators/external_command.py +0 -77
  285. union/remote/_client/auth/_authenticators/factory.py +0 -200
  286. union/remote/_client/auth/_authenticators/pkce.py +0 -515
  287. union/remote/_client/auth/_channel.py +0 -184
  288. union/remote/_client/auth/_client_config.py +0 -83
  289. union/remote/_client/auth/_default_html.py +0 -32
  290. union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  291. union/remote/_client/auth/_grpc_utils/auth_interceptor.py +0 -204
  292. union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +0 -144
  293. union/remote/_client/auth/_keyring.py +0 -154
  294. union/remote/_client/auth/_token_client.py +0 -258
  295. union/remote/_client/auth/errors.py +0 -16
  296. union/remote/_client/controlplane.py +0 -86
  297. union/remote/_data.py +0 -149
  298. union/remote/_logs.py +0 -74
  299. union/remote/_project.py +0 -86
  300. union/remote/_run.py +0 -820
  301. union/remote/_secret.py +0 -132
  302. union/remote/_task.py +0 -193
  303. union/report/__init__.py +0 -3
  304. union/report/_report.py +0 -178
  305. union/report/_template.html +0 -124
  306. union/storage/__init__.py +0 -24
  307. union/storage/_remote_fs.py +0 -34
  308. union/storage/_storage.py +0 -247
  309. union/storage/_utils.py +0 -5
  310. union/types/__init__.py +0 -11
  311. union/types/_renderer.py +0 -162
  312. union/types/_string_literals.py +0 -120
  313. union/types/_type_engine.py +0 -2131
  314. union/types/_utils.py +0 -80
  315. /union/_protos/common/authorization_pb2_grpc.py → /flyte/_protos/workflow/common_pb2_grpc.py +0 -0
  316. /union/_protos/common/identifier_pb2_grpc.py → /flyte/_protos/workflow/environment_pb2_grpc.py +0 -0
  317. /flyte/io/{structured_dataset → _structured_dataset}/__init__.py +0 -0
  318. {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/WHEEL +0 -0
  319. {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/top_level.txt +0 -0
flyte/_task.py CHANGED
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import weakref
4
5
  from dataclasses import dataclass, field, replace
5
6
  from functools import cached_property
7
+ from inspect import iscoroutinefunction
6
8
  from typing import (
7
9
  TYPE_CHECKING,
8
10
  Any,
9
- Awaitable,
10
11
  Callable,
11
12
  Coroutine,
12
13
  Dict,
@@ -15,17 +16,18 @@ from typing import (
15
16
  Literal,
16
17
  Optional,
17
18
  ParamSpec,
19
+ TypeAlias,
18
20
  TypeVar,
19
21
  Union,
20
22
  )
21
23
 
22
24
  from flyteidl.core.tasks_pb2 import DataLoadingConfig
23
25
 
26
+ from flyte._pod import PodTemplate
24
27
  from flyte.errors import RuntimeSystemError, RuntimeUserError
25
28
 
26
29
  from ._cache import Cache, CacheRequest
27
30
  from ._context import internal_ctx
28
- from ._datastructures import NativeInterface, SerializationContext
29
31
  from ._doc import Documentation
30
32
  from ._image import Image
31
33
  from ._resources import Resources
@@ -33,15 +35,18 @@ from ._retry import RetryStrategy
33
35
  from ._reusable_environment import ReusePolicy
34
36
  from ._secret import SecretRequest
35
37
  from ._timeout import TimeoutType
38
+ from .models import NativeInterface, SerializationContext
36
39
 
37
40
  if TYPE_CHECKING:
38
- from kubernetes.client import V1PodTemplate
39
-
40
41
  from ._task_environment import TaskEnvironment
41
42
 
42
43
  P = ParamSpec("P") # capture the function's parameters
43
44
  R = TypeVar("R") # return type
44
45
 
46
+ AsyncFunctionType: TypeAlias = Callable[P, Coroutine[Any, Any, R]]
47
+ SyncFunctionType: TypeAlias = Callable[P, R]
48
+ FunctionTypes: TypeAlias = Union[AsyncFunctionType, SyncFunctionType]
49
+
45
50
 
46
51
  @dataclass(kw_only=True)
47
52
  class TaskTemplate(Generic[P, R]):
@@ -78,6 +83,7 @@ class TaskTemplate(Generic[P, R]):
78
83
 
79
84
  name: str
80
85
  interface: NativeInterface
86
+ friendly_name: str = ""
81
87
  task_type: str = "python"
82
88
  task_type_version: int = 0
83
89
  image: Union[str, Image, Literal["auto"]] = "auto"
@@ -90,24 +96,17 @@ class TaskTemplate(Generic[P, R]):
90
96
  env: Optional[Dict[str, str]] = None
91
97
  secrets: Optional[SecretRequest] = None
92
98
  timeout: Optional[TimeoutType] = None
93
- primary_container_name: str = "primary"
94
- pod_template: Optional[Union[str, V1PodTemplate]] = None
99
+ pod_template: Optional[Union[str, PodTemplate]] = None
95
100
  report: bool = False
96
101
 
97
102
  parent_env: Optional[weakref.ReferenceType[TaskEnvironment]] = None
98
103
  local: bool = field(default=False, init=False)
99
104
  ref: bool = field(default=False, init=False, repr=False, compare=False)
100
105
 
101
- def __post_init__(self):
102
- # If pod_template is set to a pod, verify
103
- if self.pod_template is not None and not isinstance(self.pod_template, str):
104
- try:
105
- from kubernetes.client import V1PodTemplate # noqa: F401
106
- except ImportError as e:
107
- raise ImportError(
108
- "kubernetes is not installed, please install kubernetes package to use pod_template"
109
- ) from e
106
+ # Only used in python 3.10 and 3.11, where we cannot use markcoroutinefunction
107
+ _call_as_synchronous: bool = False
110
108
 
109
+ def __post_init__(self):
111
110
  # Auto set the image based on the image request
112
111
  if self.image == "auto":
113
112
  self.image = Image.auto()
@@ -128,6 +127,10 @@ class TaskTemplate(Generic[P, R]):
128
127
  if isinstance(self.retries, int):
129
128
  self.retries = RetryStrategy(count=self.retries)
130
129
 
130
+ if self.friendly_name == "":
131
+ # If friendly_name is not set, use the name of the task
132
+ self.friendly_name = self.name
133
+
131
134
  def __getstate__(self):
132
135
  """
133
136
  This method is called when the object is pickled. We need to remove the parent_env reference
@@ -208,13 +211,60 @@ class TaskTemplate(Generic[P, R]):
208
211
  def native_interface(self) -> NativeInterface:
209
212
  return self.interface
210
213
 
211
- async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R]:
214
+ async def aio(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
215
+ """
216
+ The aio function allows executing "sync" tasks, in an async context. This helps with migrating v1 defined sync
217
+ tasks to be used within an asyncio parent task.
218
+ This function will also re-raise exceptions from the underlying task.
219
+
220
+ Example:
221
+ ```python
222
+ @env.task
223
+ def my_legacy_task(x: int) -> int:
224
+ return x
225
+
226
+ @env.task
227
+ async def my_new_parent_task(n: int) -> List[int]:
228
+ collect = []
229
+ for x in range(n):
230
+ collect.append(my_legacy_task.aio(x))
231
+ return asyncio.gather(*collect)
232
+ ```
233
+ :param args:
234
+ :param kwargs:
235
+ :return:
236
+ """
237
+
238
+ ctx = internal_ctx()
239
+ if ctx.is_task_context():
240
+ from ._internal.controllers import get_controller
241
+
242
+ # If we are in a task context, that implies we are executing a Run.
243
+ # In this scenario, we should submit the task to the controller.
244
+ controller = get_controller()
245
+ if controller:
246
+ if self._call_as_synchronous:
247
+ fut = controller.submit_sync(self, *args, **kwargs)
248
+ asyncio_future = asyncio.wrap_future(fut) # Wrap the future to make it awaitable
249
+ return await asyncio_future
250
+ else:
251
+ return await controller.submit(self, *args, **kwargs)
252
+ else:
253
+ raise RuntimeSystemError("BadContext", "Controller is not initialized.")
254
+ else:
255
+ # Local execute, just stay out of the way, but because .aio is used, we want to return an awaitable,
256
+ # even for synchronous tasks. This is to support migration.
257
+ return self.forward(*args, **kwargs)
258
+
259
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
212
260
  """
213
261
  This is the entrypoint for an async function task at runtime. It will be called during an execution.
214
262
  Please do not override this method, if you simply want to modify the execution behavior, override the
215
263
  execute method.
216
264
 
217
- # TODO lets provide one hook to implement, _pre, _execute and _post. We do not want actual execute to
265
+ This needs to be overridable to maybe be async.
266
+ The returned thing from here needs to be an awaitable if the underlying task is async, and a regular object
267
+ if the task is not.
218
268
  """
219
269
  try:
220
270
  ctx = internal_ctx()
@@ -224,10 +274,19 @@ class TaskTemplate(Generic[P, R]):
224
274
  # We will also check if we are not initialized, It is not expected to be not initialized
225
275
  from ._internal.controllers import get_controller
226
276
 
227
- controller = await get_controller()
228
- if controller:
229
- return await controller.submit(self, *args, **kwargs)
230
- return await self.execute(*args, **kwargs)
277
+ controller = get_controller()
278
+ if not controller:
279
+ raise RuntimeSystemError("BadContext", "Controller is not initialized.")
280
+
281
+ if self._call_as_synchronous:
282
+ fut = controller.submit_sync(self, *args, **kwargs)
283
+ x = fut.result(None)
284
+ return x
285
+ else:
286
+ return controller.submit(self, *args, **kwargs)
287
+ else:
288
+ # If not in task context, purely function run, stay out of the way
289
+ return self.forward(*args, **kwargs)
231
290
  except RuntimeSystemError:
232
291
  raise
233
292
  except RuntimeUserError:
@@ -235,6 +294,17 @@ class TaskTemplate(Generic[P, R]):
235
294
  except Exception as e:
236
295
  raise RuntimeUserError(type(e).__name__, str(e)) from e
237
296
 
297
+ def forward(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
298
+ """
299
+ Think of this as a local execute method for your task. This function will be invoked by the __call__ method
300
+ when not in a Flyte task execution context. See the implementation below for an example.
301
+
302
+ :param args:
303
+ :param kwargs:
304
+ :return:
305
+ """
306
+ raise NotImplementedError
307
+
238
308
  def override(
239
309
  self,
240
310
  *,
@@ -290,26 +360,38 @@ class AsyncFunctionTaskTemplate(TaskTemplate[P, R]):
290
360
  is decorated with the task decorator.
291
361
  """
292
362
 
293
- func: Callable[P, Awaitable[R]]
363
+ func: FunctionTypes
364
+
365
+ def __post_init__(self):
366
+ super().__post_init__()
367
+ if not iscoroutinefunction(self.func):
368
+ self._call_as_synchronous = True
294
369
 
295
370
  @cached_property
296
371
  def native_interface(self) -> NativeInterface:
297
372
  return NativeInterface.from_callable(self.func)
298
373
 
374
+ def forward(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
375
+ # In local execution, we want to just call the function. Note we're not awaiting anything here.
376
+ # If the function was a coroutine function, the coroutine is returned and the await that the caller has
377
+ # in front of the task invocation will handle the awaiting.
378
+ return self.func(*args, **kwargs)
379
+
299
380
  async def execute(self, *args: P.args, **kwargs: P.kwargs) -> R:
300
381
  """
301
382
  This is the execute method that will be called when the task is invoked. It will call the actual function.
302
383
  # TODO We may need to keep this as the bare func execute, and need a pre and post execute some other func.
303
384
  """
385
+
304
386
  ctx = internal_ctx()
387
+ assert ctx.data.task_context is not None, "Function should have already returned if not in a task context"
305
388
  ctx_data = await self.pre(*args, **kwargs)
306
- if ctx.data.task_context is not None:
307
- tctx = ctx.data.task_context.replace(data=ctx_data)
308
- with ctx.replace_task_context(tctx):
389
+ tctx = ctx.data.task_context.replace(data=ctx_data)
390
+ with ctx.replace_task_context(tctx):
391
+ if iscoroutinefunction(self.func):
309
392
  v = await self.func(*args, **kwargs)
310
- await self.post(v)
311
- else:
312
- v = await self.func(*args, **kwargs)
393
+ else:
394
+ v = self.func(*args, **kwargs)
313
395
  await self.post(v)
314
396
  return v
315
397
 
@@ -1,16 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  import weakref
5
4
  from dataclasses import dataclass, field, replace
6
5
  from datetime import timedelta
7
- from functools import wraps
8
- from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Literal, Optional, ParamSpec, TypeVar, Union, cast
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Any,
9
+ Callable,
10
+ Dict,
11
+ List,
12
+ Literal,
13
+ Optional,
14
+ Union,
15
+ cast,
16
+ )
9
17
 
10
18
  import rich.repr
11
19
 
12
20
  from ._cache import CacheRequest
13
- from ._datastructures import NativeInterface
14
21
  from ._doc import Documentation
15
22
  from ._environment import Environment
16
23
  from ._image import Image
@@ -19,12 +26,12 @@ from ._retry import RetryStrategy
19
26
  from ._reusable_environment import ReusePolicy
20
27
  from ._secret import SecretRequest
21
28
  from ._task import AsyncFunctionTaskTemplate, TaskTemplate
29
+ from .models import NativeInterface
22
30
 
23
31
  if TYPE_CHECKING:
24
32
  from kubernetes.client import V1PodTemplate
25
33
 
26
- P = ParamSpec("P") # capture the function's parameters
27
- R = TypeVar("R") # return type
34
+ from ._task import FunctionTypes, P, R
28
35
 
29
36
 
30
37
  @rich.repr.auto
@@ -47,14 +54,14 @@ class TaskEnvironment(Environment):
47
54
  :param resources: Resources to allocate for the environment.
48
55
  :param env: Environment variables to set for the environment.
49
56
  :param secrets: Secrets to inject into the environment.
50
- :param env_dep_hints: Environment dependencies to hint, so when you deploy the environment, the dependencies are
57
+ :param depends_on: Environment dependencies to hint, so when you deploy the environment, the dependencies are
51
58
  also deployed. This is useful when you have a set of environments that depend on each other.
52
59
  :param cache: Cache policy for the environment.
53
60
  :param reusable: Reuse policy for the environment, if set, a python process may be reused for multiple tasks.
54
61
  """
55
62
 
56
63
  cache: Union[CacheRequest] = "auto"
57
- reusable: Union[ReusePolicy, Literal["auto"], None] = None
64
+ reusable: ReusePolicy | None = None
58
65
  # TODO Shall we make this union of string or env? This way we can lookup the env by module/file:name
59
66
  # TODO also we could add list of files that are used by this environment
60
67
 
@@ -65,32 +72,42 @@ class TaskEnvironment(Environment):
65
72
  name: str,
66
73
  image: Optional[Union[str, Image, Literal["auto"]]] = None,
67
74
  resources: Optional[Resources] = None,
68
- cache: Union[CacheRequest, None] = None,
69
75
  env: Optional[Dict[str, str]] = None,
70
- reusable: Union[ReusePolicy, None] = None,
71
76
  secrets: Optional[SecretRequest] = None,
72
- env_dep_hints: Optional[List[Environment]] = None,
77
+ depends_on: Optional[List[Environment]] = None,
78
+ **kwargs: Any,
73
79
  ) -> TaskEnvironment:
74
80
  """
75
- Clone the environment with new settings.
81
+ Clone the TaskEnvironment with new parameters.
82
+ besides the base environment parameters, you can override, kwargs like `cache`, `reusable`, etc.
83
+
76
84
  """
77
- if image is None:
78
- image = self.image
79
- else:
80
- image = "auto"
81
- return replace(
82
- self,
83
- cache=cache if cache else "auto",
84
- reusable=reusable,
85
- name=name,
86
- image=image,
87
- resources=resources,
88
- env=env,
89
- secrets=secrets,
90
- env_dep_hints=env_dep_hints if env_dep_hints else [],
91
- )
92
-
93
- def _task(
85
+ cache = kwargs.pop("cache", None)
86
+ reusable = kwargs.pop("reusable", None)
87
+
88
+ # validate unknown kwargs if needed
89
+ if kwargs:
90
+ raise TypeError(f"Unexpected keyword arguments: {list(kwargs.keys())}")
91
+
92
+ kwargs = self._get_kwargs()
93
+ kwargs["name"] = name
94
+ if image is not None:
95
+ kwargs["image"] = image
96
+ if resources is not None:
97
+ kwargs["resources"] = resources
98
+ if cache is not None:
99
+ kwargs["cache"] = cache
100
+ if env is not None:
101
+ kwargs["env"] = env
102
+ if reusable is not None:
103
+ kwargs["reusable"] = reusable
104
+ if secrets is not None:
105
+ kwargs["secrets"] = secrets
106
+ if depends_on is not None:
107
+ kwargs["depends_on"] = depends_on
108
+ return replace(self, **kwargs)
109
+
110
+ def task(
94
111
  self,
95
112
  _func=None,
96
113
  *,
@@ -104,7 +121,8 @@ class TaskEnvironment(Environment):
104
121
  report: bool = False,
105
122
  ) -> Union[AsyncFunctionTaskTemplate, Callable[P, R]]:
106
123
  """
107
- :param name: Optional The name of the task (defaults to the function name)
124
+ :param _func: Optional The function to decorate. If not provided, the decorator will return a callable that
125
+ :param name: Optional A friendly name for the task (defaults to the function name)
108
126
  :param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the
109
127
  task.
110
128
  :param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
@@ -119,25 +137,12 @@ class TaskEnvironment(Environment):
119
137
  if pod_template is not None:
120
138
  raise ValueError("Cannot set pod_template when environment is reusable.")
121
139
 
122
- def decorator(func: Callable[P, Awaitable[R]]) -> AsyncFunctionTaskTemplate[P, R]:
123
- task_name = name or func.__name__
124
- task_name = self.name + "." + task_name
125
- if len(task_name) > 30:
126
- # delete this if we can remove the restriction that task names must be <= 30 characters
127
- task_name = task_name[-30:]
128
-
129
- @wraps(func)
130
- async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
131
- return await func(*args, **kwargs)
132
-
133
- if not asyncio.iscoroutinefunction(func):
134
- raise TypeError(
135
- f"Function {func.__name__} is not a coroutine function. Use @env.task decorator for async tasks."
136
- f"You can simply mark your function as async def {func.__name__} to make it a coroutine function, "
137
- f"it is ok to write sync code in async functions, but not the other way around."
138
- )
139
- tmpl = AsyncFunctionTaskTemplate(
140
- func=wrapper,
140
+ def decorator(func: FunctionTypes) -> AsyncFunctionTaskTemplate[P, R]:
141
+ friendly_name = name or func.__name__
142
+ task_name = self.name + "." + func.__name__
143
+
144
+ tmpl: AsyncFunctionTaskTemplate = AsyncFunctionTaskTemplate(
145
+ func=func,
141
146
  name=task_name,
142
147
  image=self.image,
143
148
  resources=self.resources,
@@ -152,6 +157,7 @@ class TaskEnvironment(Environment):
152
157
  parent_env=weakref.ref(self),
153
158
  interface=NativeInterface.from_callable(func),
154
159
  report=report,
160
+ friendly_name=friendly_name,
155
161
  )
156
162
  self._tasks[task_name] = tmpl
157
163
  return tmpl
@@ -160,29 +166,6 @@ class TaskEnvironment(Environment):
160
166
  return cast(AsyncFunctionTaskTemplate, decorator)
161
167
  return cast(AsyncFunctionTaskTemplate, decorator(_func))
162
168
 
163
- @property
164
- def task(self) -> Callable:
165
- """
166
- Decorator to create a new task with the environment settings.
167
- The task will be executed in its own container with the specified image, resources, and environment variables,
168
- unless reusePolicy is set, in which case the same container will be reused for all tasks with the same
169
- environment settings.
170
-
171
- :param name: Optional The name of the task (defaults to the function name)
172
- :param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the
173
- task.
174
- :param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
175
- :param docs: Optional The documentation for the task, if not provided the function docstring will be used.
176
- :param secrets: Optional The secrets that will be injected into the task at runtime.
177
- :param timeout: Optional The timeout for the task.
178
- :param pod_template: Optional The pod template for the task, if not provided the default pod template will be
179
- used.
180
- :param report: Optional Whether to generate the html report for the task, defaults to False.
181
-
182
- :return: New Task instance or Task decorator
183
- """
184
- return self._task
185
-
186
169
  @property
187
170
  def tasks(self) -> Dict[str, TaskTemplate]:
188
171
  """
flyte/_trace.py CHANGED
@@ -4,7 +4,7 @@ import time
4
4
  from datetime import timedelta
5
5
  from typing import Any, AsyncGenerator, AsyncIterator, Awaitable, Callable, TypeGuard, TypeVar, Union, cast
6
6
 
7
- from flyte._datastructures import NativeInterface
7
+ from flyte.models import NativeInterface
8
8
 
9
9
  T = TypeVar("T")
10
10
 
@@ -14,7 +14,6 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
14
14
  A decorator that traces function execution with timing information.
15
15
  Works with regular functions, async functions, and async generators/iterators.
16
16
  """
17
- func_name = func.__name__
18
17
 
19
18
  @functools.wraps(func)
20
19
  def wrapper_sync(*args: Any, **kwargs: Any) -> Any:
@@ -31,9 +30,9 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
31
30
  # We will also check if we are not initialized, It is not expected to be not initialized
32
31
  from ._internal.controllers import get_controller
33
32
 
34
- controller = await get_controller()
33
+ controller = get_controller()
35
34
  iface = NativeInterface.from_callable(func)
36
- info, ok = await controller.get_action_outputs(iface, func_name, *args, **kwargs)
35
+ info, ok = await controller.get_action_outputs(iface, func, *args, **kwargs)
37
36
  if ok:
38
37
  if info.output:
39
38
  return info.output
@@ -74,9 +73,9 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
74
73
  # We will also check if we are not initialized, It is not expected to be not initialized
75
74
  from ._internal.controllers import get_controller
76
75
 
77
- controller = await get_controller()
76
+ controller = get_controller()
78
77
  iface = NativeInterface.from_callable(func)
79
- info, ok = await controller.get_action_outputs(iface, func_name, *args, **kwargs)
78
+ info, ok = await controller.get_action_outputs(iface, func, *args, **kwargs)
80
79
  if ok:
81
80
  if info.output:
82
81
  for item in info.output:
@@ -88,17 +87,12 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
88
87
  items = []
89
88
  result = func(*args, **kwargs)
90
89
  # TODO ideally we should use streaming into the type-engine so that it stream uploads large blocks
91
- if inspect.isasyncgen(result):
90
+ if inspect.isasyncgen(result) or is_async_iterable(result):
92
91
  # If it's directly an async generator
93
92
  async_iter = result
94
93
  async for item in async_iter:
95
94
  items.append(item)
96
95
  yield item
97
- elif is_async_iterable(result):
98
- # If it's an async iterable (has __aiter__)
99
- async for item in result:
100
- items.append(item)
101
- yield item
102
96
  duration = time.time() - start_time
103
97
  info.add_outputs(items, timedelta(seconds=duration))
104
98
  await controller.record_trace(info)
@@ -118,10 +112,8 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
118
112
  # Choose the appropriate wrapper based on the function type
119
113
  if inspect.iscoroutinefunction(func):
120
114
  # This handles async functions that return normal values
121
- print(f"Coroutine function {func.__name__}")
122
115
  return cast(Callable[..., T], wrapper_async)
123
116
  elif inspect.isasyncgenfunction(func):
124
- print(f"Async generator function {func.__name__}")
125
117
  return cast(Callable[..., T], wrapper_async_iterator)
126
118
  else:
127
119
  # For regular sync functions
flyte/_utils/__init__.py CHANGED
@@ -4,17 +4,23 @@ Internal utility functions.
4
4
  Except for logging, modules in this package should not depend on any other part of the repo.
5
5
  """
6
6
 
7
+ from .async_cache import AsyncLRUCache
7
8
  from .coro_management import run_coros
8
9
  from .file_handling import filehash_update, update_hasher_for_source
9
10
  from .helpers import get_cwd_editable_install
10
11
  from .lazy_module import lazy_module
12
+ from .org_discovery import hostname_from_url, org_from_endpoint, sanitize_endpoint
11
13
  from .uv_script_parser import parse_uv_script_file
12
14
 
13
15
  __all__ = [
16
+ "AsyncLRUCache",
14
17
  "filehash_update",
15
18
  "get_cwd_editable_install",
19
+ "hostname_from_url",
16
20
  "lazy_module",
21
+ "org_from_endpoint",
17
22
  "parse_uv_script_file",
18
23
  "run_coros",
24
+ "sanitize_endpoint",
19
25
  "update_hasher_for_source",
20
26
  ]