flyte 0.0.1b0__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 (390) hide show
  1. flyte/__init__.py +62 -0
  2. flyte/_api_commons.py +3 -0
  3. flyte/_bin/__init__.py +0 -0
  4. flyte/_bin/runtime.py +126 -0
  5. flyte/_build.py +25 -0
  6. flyte/_cache/__init__.py +12 -0
  7. flyte/_cache/cache.py +146 -0
  8. flyte/_cache/defaults.py +9 -0
  9. flyte/_cache/policy_function_body.py +42 -0
  10. flyte/_cli/__init__.py +0 -0
  11. flyte/_cli/_common.py +287 -0
  12. flyte/_cli/_create.py +42 -0
  13. flyte/_cli/_delete.py +23 -0
  14. flyte/_cli/_deploy.py +140 -0
  15. flyte/_cli/_get.py +235 -0
  16. flyte/_cli/_run.py +152 -0
  17. flyte/_cli/main.py +72 -0
  18. flyte/_code_bundle/__init__.py +8 -0
  19. flyte/_code_bundle/_ignore.py +113 -0
  20. flyte/_code_bundle/_packaging.py +187 -0
  21. flyte/_code_bundle/_utils.py +339 -0
  22. flyte/_code_bundle/bundle.py +178 -0
  23. flyte/_context.py +146 -0
  24. flyte/_datastructures.py +342 -0
  25. flyte/_deploy.py +202 -0
  26. flyte/_doc.py +29 -0
  27. flyte/_docstring.py +32 -0
  28. flyte/_environment.py +43 -0
  29. flyte/_group.py +31 -0
  30. flyte/_hash.py +23 -0
  31. flyte/_image.py +760 -0
  32. flyte/_initialize.py +634 -0
  33. flyte/_interface.py +84 -0
  34. flyte/_internal/__init__.py +3 -0
  35. flyte/_internal/controllers/__init__.py +115 -0
  36. flyte/_internal/controllers/_local_controller.py +118 -0
  37. flyte/_internal/controllers/_trace.py +40 -0
  38. flyte/_internal/controllers/pbhash.py +39 -0
  39. flyte/_internal/controllers/remote/__init__.py +40 -0
  40. flyte/_internal/controllers/remote/_action.py +141 -0
  41. flyte/_internal/controllers/remote/_client.py +43 -0
  42. flyte/_internal/controllers/remote/_controller.py +361 -0
  43. flyte/_internal/controllers/remote/_core.py +402 -0
  44. flyte/_internal/controllers/remote/_informer.py +361 -0
  45. flyte/_internal/controllers/remote/_service_protocol.py +50 -0
  46. flyte/_internal/imagebuild/__init__.py +11 -0
  47. flyte/_internal/imagebuild/docker_builder.py +416 -0
  48. flyte/_internal/imagebuild/image_builder.py +241 -0
  49. flyte/_internal/imagebuild/remote_builder.py +0 -0
  50. flyte/_internal/resolvers/__init__.py +0 -0
  51. flyte/_internal/resolvers/_task_module.py +54 -0
  52. flyte/_internal/resolvers/common.py +31 -0
  53. flyte/_internal/resolvers/default.py +28 -0
  54. flyte/_internal/runtime/__init__.py +0 -0
  55. flyte/_internal/runtime/convert.py +199 -0
  56. flyte/_internal/runtime/entrypoints.py +135 -0
  57. flyte/_internal/runtime/io.py +136 -0
  58. flyte/_internal/runtime/resources_serde.py +138 -0
  59. flyte/_internal/runtime/task_serde.py +210 -0
  60. flyte/_internal/runtime/taskrunner.py +190 -0
  61. flyte/_internal/runtime/types_serde.py +54 -0
  62. flyte/_logging.py +124 -0
  63. flyte/_protos/__init__.py +0 -0
  64. flyte/_protos/common/authorization_pb2.py +66 -0
  65. flyte/_protos/common/authorization_pb2.pyi +108 -0
  66. flyte/_protos/common/authorization_pb2_grpc.py +4 -0
  67. flyte/_protos/common/identifier_pb2.py +71 -0
  68. flyte/_protos/common/identifier_pb2.pyi +82 -0
  69. flyte/_protos/common/identifier_pb2_grpc.py +4 -0
  70. flyte/_protos/common/identity_pb2.py +48 -0
  71. flyte/_protos/common/identity_pb2.pyi +72 -0
  72. flyte/_protos/common/identity_pb2_grpc.py +4 -0
  73. flyte/_protos/common/list_pb2.py +36 -0
  74. flyte/_protos/common/list_pb2.pyi +69 -0
  75. flyte/_protos/common/list_pb2_grpc.py +4 -0
  76. flyte/_protos/common/policy_pb2.py +37 -0
  77. flyte/_protos/common/policy_pb2.pyi +27 -0
  78. flyte/_protos/common/policy_pb2_grpc.py +4 -0
  79. flyte/_protos/common/role_pb2.py +37 -0
  80. flyte/_protos/common/role_pb2.pyi +53 -0
  81. flyte/_protos/common/role_pb2_grpc.py +4 -0
  82. flyte/_protos/common/runtime_version_pb2.py +28 -0
  83. flyte/_protos/common/runtime_version_pb2.pyi +24 -0
  84. flyte/_protos/common/runtime_version_pb2_grpc.py +4 -0
  85. flyte/_protos/logs/dataplane/payload_pb2.py +96 -0
  86. flyte/_protos/logs/dataplane/payload_pb2.pyi +168 -0
  87. flyte/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
  88. flyte/_protos/secret/definition_pb2.py +49 -0
  89. flyte/_protos/secret/definition_pb2.pyi +93 -0
  90. flyte/_protos/secret/definition_pb2_grpc.py +4 -0
  91. flyte/_protos/secret/payload_pb2.py +62 -0
  92. flyte/_protos/secret/payload_pb2.pyi +94 -0
  93. flyte/_protos/secret/payload_pb2_grpc.py +4 -0
  94. flyte/_protos/secret/secret_pb2.py +38 -0
  95. flyte/_protos/secret/secret_pb2.pyi +6 -0
  96. flyte/_protos/secret/secret_pb2_grpc.py +198 -0
  97. flyte/_protos/secret/secret_pb2_grpc_grpc.py +198 -0
  98. flyte/_protos/validate/validate/validate_pb2.py +76 -0
  99. flyte/_protos/workflow/node_execution_service_pb2.py +26 -0
  100. flyte/_protos/workflow/node_execution_service_pb2.pyi +4 -0
  101. flyte/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
  102. flyte/_protos/workflow/queue_service_pb2.py +106 -0
  103. flyte/_protos/workflow/queue_service_pb2.pyi +141 -0
  104. flyte/_protos/workflow/queue_service_pb2_grpc.py +172 -0
  105. flyte/_protos/workflow/run_definition_pb2.py +128 -0
  106. flyte/_protos/workflow/run_definition_pb2.pyi +310 -0
  107. flyte/_protos/workflow/run_definition_pb2_grpc.py +4 -0
  108. flyte/_protos/workflow/run_logs_service_pb2.py +41 -0
  109. flyte/_protos/workflow/run_logs_service_pb2.pyi +28 -0
  110. flyte/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
  111. flyte/_protos/workflow/run_service_pb2.py +133 -0
  112. flyte/_protos/workflow/run_service_pb2.pyi +175 -0
  113. flyte/_protos/workflow/run_service_pb2_grpc.py +412 -0
  114. flyte/_protos/workflow/state_service_pb2.py +58 -0
  115. flyte/_protos/workflow/state_service_pb2.pyi +71 -0
  116. flyte/_protos/workflow/state_service_pb2_grpc.py +138 -0
  117. flyte/_protos/workflow/task_definition_pb2.py +72 -0
  118. flyte/_protos/workflow/task_definition_pb2.pyi +65 -0
  119. flyte/_protos/workflow/task_definition_pb2_grpc.py +4 -0
  120. flyte/_protos/workflow/task_service_pb2.py +44 -0
  121. flyte/_protos/workflow/task_service_pb2.pyi +31 -0
  122. flyte/_protos/workflow/task_service_pb2_grpc.py +104 -0
  123. flyte/_resources.py +226 -0
  124. flyte/_retry.py +32 -0
  125. flyte/_reusable_environment.py +25 -0
  126. flyte/_run.py +411 -0
  127. flyte/_secret.py +61 -0
  128. flyte/_task.py +367 -0
  129. flyte/_task_environment.py +200 -0
  130. flyte/_timeout.py +47 -0
  131. flyte/_tools.py +27 -0
  132. flyte/_trace.py +128 -0
  133. flyte/_utils/__init__.py +20 -0
  134. flyte/_utils/asyn.py +119 -0
  135. flyte/_utils/coro_management.py +25 -0
  136. flyte/_utils/file_handling.py +72 -0
  137. flyte/_utils/helpers.py +108 -0
  138. flyte/_utils/lazy_module.py +54 -0
  139. flyte/_utils/uv_script_parser.py +49 -0
  140. flyte/_version.py +21 -0
  141. flyte/connectors/__init__.py +0 -0
  142. flyte/errors.py +143 -0
  143. flyte/extras/__init__.py +5 -0
  144. flyte/extras/_container.py +273 -0
  145. flyte/io/__init__.py +11 -0
  146. flyte/io/_dataframe.py +0 -0
  147. flyte/io/_dir.py +448 -0
  148. flyte/io/_file.py +468 -0
  149. flyte/io/pickle/__init__.py +0 -0
  150. flyte/io/pickle/transformer.py +117 -0
  151. flyte/io/structured_dataset/__init__.py +129 -0
  152. flyte/io/structured_dataset/basic_dfs.py +219 -0
  153. flyte/io/structured_dataset/structured_dataset.py +1061 -0
  154. flyte/py.typed +0 -0
  155. flyte/remote/__init__.py +25 -0
  156. flyte/remote/_client/__init__.py +0 -0
  157. flyte/remote/_client/_protocols.py +131 -0
  158. flyte/remote/_client/auth/__init__.py +12 -0
  159. flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
  160. flyte/remote/_client/auth/_authenticators/base.py +397 -0
  161. flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
  162. flyte/remote/_client/auth/_authenticators/device_code.py +118 -0
  163. flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
  164. flyte/remote/_client/auth/_authenticators/factory.py +200 -0
  165. flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
  166. flyte/remote/_client/auth/_channel.py +184 -0
  167. flyte/remote/_client/auth/_client_config.py +83 -0
  168. flyte/remote/_client/auth/_default_html.py +32 -0
  169. flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  170. flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
  171. flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
  172. flyte/remote/_client/auth/_keyring.py +143 -0
  173. flyte/remote/_client/auth/_token_client.py +260 -0
  174. flyte/remote/_client/auth/errors.py +16 -0
  175. flyte/remote/_client/controlplane.py +95 -0
  176. flyte/remote/_console.py +18 -0
  177. flyte/remote/_data.py +155 -0
  178. flyte/remote/_logs.py +116 -0
  179. flyte/remote/_project.py +86 -0
  180. flyte/remote/_run.py +873 -0
  181. flyte/remote/_secret.py +132 -0
  182. flyte/remote/_task.py +227 -0
  183. flyte/report/__init__.py +3 -0
  184. flyte/report/_report.py +178 -0
  185. flyte/report/_template.html +124 -0
  186. flyte/storage/__init__.py +24 -0
  187. flyte/storage/_remote_fs.py +34 -0
  188. flyte/storage/_storage.py +251 -0
  189. flyte/storage/_utils.py +5 -0
  190. flyte/types/__init__.py +13 -0
  191. flyte/types/_interface.py +25 -0
  192. flyte/types/_renderer.py +162 -0
  193. flyte/types/_string_literals.py +120 -0
  194. flyte/types/_type_engine.py +2210 -0
  195. flyte/types/_utils.py +80 -0
  196. flyte-0.0.1b0.dist-info/METADATA +179 -0
  197. flyte-0.0.1b0.dist-info/RECORD +390 -0
  198. flyte-0.0.1b0.dist-info/WHEEL +5 -0
  199. flyte-0.0.1b0.dist-info/entry_points.txt +3 -0
  200. flyte-0.0.1b0.dist-info/top_level.txt +1 -0
  201. union/__init__.py +54 -0
  202. union/_api_commons.py +3 -0
  203. union/_bin/__init__.py +0 -0
  204. union/_bin/runtime.py +113 -0
  205. union/_build.py +25 -0
  206. union/_cache/__init__.py +12 -0
  207. union/_cache/cache.py +141 -0
  208. union/_cache/defaults.py +9 -0
  209. union/_cache/policy_function_body.py +42 -0
  210. union/_cli/__init__.py +0 -0
  211. union/_cli/_common.py +263 -0
  212. union/_cli/_create.py +40 -0
  213. union/_cli/_delete.py +23 -0
  214. union/_cli/_deploy.py +120 -0
  215. union/_cli/_get.py +162 -0
  216. union/_cli/_params.py +579 -0
  217. union/_cli/_run.py +150 -0
  218. union/_cli/main.py +72 -0
  219. union/_code_bundle/__init__.py +8 -0
  220. union/_code_bundle/_ignore.py +113 -0
  221. union/_code_bundle/_packaging.py +187 -0
  222. union/_code_bundle/_utils.py +342 -0
  223. union/_code_bundle/bundle.py +176 -0
  224. union/_context.py +146 -0
  225. union/_datastructures.py +295 -0
  226. union/_deploy.py +185 -0
  227. union/_doc.py +29 -0
  228. union/_docstring.py +26 -0
  229. union/_environment.py +43 -0
  230. union/_group.py +31 -0
  231. union/_hash.py +23 -0
  232. union/_image.py +760 -0
  233. union/_initialize.py +585 -0
  234. union/_interface.py +84 -0
  235. union/_internal/__init__.py +3 -0
  236. union/_internal/controllers/__init__.py +77 -0
  237. union/_internal/controllers/_local_controller.py +77 -0
  238. union/_internal/controllers/pbhash.py +39 -0
  239. union/_internal/controllers/remote/__init__.py +40 -0
  240. union/_internal/controllers/remote/_action.py +131 -0
  241. union/_internal/controllers/remote/_client.py +43 -0
  242. union/_internal/controllers/remote/_controller.py +169 -0
  243. union/_internal/controllers/remote/_core.py +341 -0
  244. union/_internal/controllers/remote/_informer.py +260 -0
  245. union/_internal/controllers/remote/_service_protocol.py +44 -0
  246. union/_internal/imagebuild/__init__.py +11 -0
  247. union/_internal/imagebuild/docker_builder.py +416 -0
  248. union/_internal/imagebuild/image_builder.py +243 -0
  249. union/_internal/imagebuild/remote_builder.py +0 -0
  250. union/_internal/resolvers/__init__.py +0 -0
  251. union/_internal/resolvers/_task_module.py +31 -0
  252. union/_internal/resolvers/common.py +24 -0
  253. union/_internal/resolvers/default.py +27 -0
  254. union/_internal/runtime/__init__.py +0 -0
  255. union/_internal/runtime/convert.py +163 -0
  256. union/_internal/runtime/entrypoints.py +121 -0
  257. union/_internal/runtime/io.py +136 -0
  258. union/_internal/runtime/resources_serde.py +134 -0
  259. union/_internal/runtime/task_serde.py +202 -0
  260. union/_internal/runtime/taskrunner.py +179 -0
  261. union/_internal/runtime/types_serde.py +53 -0
  262. union/_logging.py +124 -0
  263. union/_protos/__init__.py +0 -0
  264. union/_protos/common/authorization_pb2.py +66 -0
  265. union/_protos/common/authorization_pb2.pyi +106 -0
  266. union/_protos/common/authorization_pb2_grpc.py +4 -0
  267. union/_protos/common/identifier_pb2.py +71 -0
  268. union/_protos/common/identifier_pb2.pyi +82 -0
  269. union/_protos/common/identifier_pb2_grpc.py +4 -0
  270. union/_protos/common/identity_pb2.py +48 -0
  271. union/_protos/common/identity_pb2.pyi +72 -0
  272. union/_protos/common/identity_pb2_grpc.py +4 -0
  273. union/_protos/common/list_pb2.py +36 -0
  274. union/_protos/common/list_pb2.pyi +69 -0
  275. union/_protos/common/list_pb2_grpc.py +4 -0
  276. union/_protos/common/policy_pb2.py +37 -0
  277. union/_protos/common/policy_pb2.pyi +27 -0
  278. union/_protos/common/policy_pb2_grpc.py +4 -0
  279. union/_protos/common/role_pb2.py +37 -0
  280. union/_protos/common/role_pb2.pyi +51 -0
  281. union/_protos/common/role_pb2_grpc.py +4 -0
  282. union/_protos/common/runtime_version_pb2.py +28 -0
  283. union/_protos/common/runtime_version_pb2.pyi +24 -0
  284. union/_protos/common/runtime_version_pb2_grpc.py +4 -0
  285. union/_protos/logs/dataplane/payload_pb2.py +96 -0
  286. union/_protos/logs/dataplane/payload_pb2.pyi +168 -0
  287. union/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
  288. union/_protos/secret/definition_pb2.py +49 -0
  289. union/_protos/secret/definition_pb2.pyi +93 -0
  290. union/_protos/secret/definition_pb2_grpc.py +4 -0
  291. union/_protos/secret/payload_pb2.py +62 -0
  292. union/_protos/secret/payload_pb2.pyi +94 -0
  293. union/_protos/secret/payload_pb2_grpc.py +4 -0
  294. union/_protos/secret/secret_pb2.py +38 -0
  295. union/_protos/secret/secret_pb2.pyi +6 -0
  296. union/_protos/secret/secret_pb2_grpc.py +198 -0
  297. union/_protos/validate/validate/validate_pb2.py +76 -0
  298. union/_protos/workflow/node_execution_service_pb2.py +26 -0
  299. union/_protos/workflow/node_execution_service_pb2.pyi +4 -0
  300. union/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
  301. union/_protos/workflow/queue_service_pb2.py +75 -0
  302. union/_protos/workflow/queue_service_pb2.pyi +103 -0
  303. union/_protos/workflow/queue_service_pb2_grpc.py +172 -0
  304. union/_protos/workflow/run_definition_pb2.py +100 -0
  305. union/_protos/workflow/run_definition_pb2.pyi +256 -0
  306. union/_protos/workflow/run_definition_pb2_grpc.py +4 -0
  307. union/_protos/workflow/run_logs_service_pb2.py +41 -0
  308. union/_protos/workflow/run_logs_service_pb2.pyi +28 -0
  309. union/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
  310. union/_protos/workflow/run_service_pb2.py +133 -0
  311. union/_protos/workflow/run_service_pb2.pyi +173 -0
  312. union/_protos/workflow/run_service_pb2_grpc.py +412 -0
  313. union/_protos/workflow/state_service_pb2.py +58 -0
  314. union/_protos/workflow/state_service_pb2.pyi +69 -0
  315. union/_protos/workflow/state_service_pb2_grpc.py +138 -0
  316. union/_protos/workflow/task_definition_pb2.py +72 -0
  317. union/_protos/workflow/task_definition_pb2.pyi +65 -0
  318. union/_protos/workflow/task_definition_pb2_grpc.py +4 -0
  319. union/_protos/workflow/task_service_pb2.py +44 -0
  320. union/_protos/workflow/task_service_pb2.pyi +31 -0
  321. union/_protos/workflow/task_service_pb2_grpc.py +104 -0
  322. union/_resources.py +226 -0
  323. union/_retry.py +32 -0
  324. union/_reusable_environment.py +25 -0
  325. union/_run.py +374 -0
  326. union/_secret.py +61 -0
  327. union/_task.py +354 -0
  328. union/_task_environment.py +186 -0
  329. union/_timeout.py +47 -0
  330. union/_tools.py +27 -0
  331. union/_utils/__init__.py +11 -0
  332. union/_utils/asyn.py +119 -0
  333. union/_utils/file_handling.py +71 -0
  334. union/_utils/helpers.py +46 -0
  335. union/_utils/lazy_module.py +54 -0
  336. union/_utils/uv_script_parser.py +49 -0
  337. union/_version.py +21 -0
  338. union/connectors/__init__.py +0 -0
  339. union/errors.py +128 -0
  340. union/extras/__init__.py +5 -0
  341. union/extras/_container.py +263 -0
  342. union/io/__init__.py +11 -0
  343. union/io/_dataframe.py +0 -0
  344. union/io/_dir.py +425 -0
  345. union/io/_file.py +418 -0
  346. union/io/pickle/__init__.py +0 -0
  347. union/io/pickle/transformer.py +117 -0
  348. union/io/structured_dataset/__init__.py +122 -0
  349. union/io/structured_dataset/basic_dfs.py +219 -0
  350. union/io/structured_dataset/structured_dataset.py +1057 -0
  351. union/py.typed +0 -0
  352. union/remote/__init__.py +23 -0
  353. union/remote/_client/__init__.py +0 -0
  354. union/remote/_client/_protocols.py +129 -0
  355. union/remote/_client/auth/__init__.py +12 -0
  356. union/remote/_client/auth/_authenticators/__init__.py +0 -0
  357. union/remote/_client/auth/_authenticators/base.py +391 -0
  358. union/remote/_client/auth/_authenticators/client_credentials.py +73 -0
  359. union/remote/_client/auth/_authenticators/device_code.py +120 -0
  360. union/remote/_client/auth/_authenticators/external_command.py +77 -0
  361. union/remote/_client/auth/_authenticators/factory.py +200 -0
  362. union/remote/_client/auth/_authenticators/pkce.py +515 -0
  363. union/remote/_client/auth/_channel.py +184 -0
  364. union/remote/_client/auth/_client_config.py +83 -0
  365. union/remote/_client/auth/_default_html.py +32 -0
  366. union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  367. union/remote/_client/auth/_grpc_utils/auth_interceptor.py +204 -0
  368. union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +144 -0
  369. union/remote/_client/auth/_keyring.py +154 -0
  370. union/remote/_client/auth/_token_client.py +258 -0
  371. union/remote/_client/auth/errors.py +16 -0
  372. union/remote/_client/controlplane.py +86 -0
  373. union/remote/_data.py +149 -0
  374. union/remote/_logs.py +74 -0
  375. union/remote/_project.py +86 -0
  376. union/remote/_run.py +820 -0
  377. union/remote/_secret.py +132 -0
  378. union/remote/_task.py +193 -0
  379. union/report/__init__.py +3 -0
  380. union/report/_report.py +178 -0
  381. union/report/_template.html +124 -0
  382. union/storage/__init__.py +24 -0
  383. union/storage/_remote_fs.py +34 -0
  384. union/storage/_storage.py +247 -0
  385. union/storage/_utils.py +5 -0
  386. union/types/__init__.py +11 -0
  387. union/types/_renderer.py +162 -0
  388. union/types/_string_literals.py +120 -0
  389. union/types/_type_engine.py +2131 -0
  390. union/types/_utils.py +80 -0
@@ -0,0 +1,295 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import os
5
+ import pathlib
6
+ import tempfile
7
+ from dataclasses import dataclass, field, replace
8
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Type
9
+
10
+ from union._docstring import Docstring
11
+ from union._interface import extract_return_annotation
12
+ from union._logging import logger
13
+ from union._utils.helpers import base62_encode
14
+
15
+ if TYPE_CHECKING:
16
+ from union._internal.imagebuild.image_builder import ImageCache
17
+ from union.report import Report
18
+
19
+
20
+ def generate_random_name() -> str:
21
+ """
22
+ Generate a random name for the task. This is used to create unique names for tasks.
23
+ TODO we can use unique-namer in the future, for now its just guids
24
+ """
25
+ from uuid import uuid4
26
+
27
+ return str(uuid4()) # Placeholder for actual random name generation logic
28
+
29
+
30
+ @dataclass(frozen=True, kw_only=True)
31
+ class ActionID:
32
+ """
33
+ A class representing the ID of an Action, nested within a Run. This is used to identify a specific action on a task.
34
+ """
35
+
36
+ name: str
37
+ run_name: str | None = None
38
+ project: str | None = None
39
+ domain: str | None = None
40
+ org: str | None = None
41
+
42
+ def __post_init__(self):
43
+ if self.run_name is None:
44
+ object.__setattr__(self, "run_name", self.name)
45
+
46
+ @classmethod
47
+ def create_random(cls):
48
+ name = generate_random_name()
49
+ return cls(name=name, run_name=name)
50
+
51
+ def new_sub_action(self, name: str | None = None) -> ActionID:
52
+ """
53
+ Create a new sub-run with the given name. If name is None, a random name will be generated.
54
+ """
55
+ if name is None:
56
+ name = generate_random_name()
57
+ return replace(self, name=name)
58
+
59
+ def new_sub_action_from(self, input_hash: str, group: str | None) -> ActionID:
60
+ """Make a deterministic name"""
61
+ import hashlib
62
+
63
+ components = f"{self.run_name}-{self.name}-{input_hash}" + (f"-{group}" if group else "")
64
+ # has the components into something deterministic
65
+ bytes_digest = hashlib.md5(components.encode()).digest()
66
+ new_name = base62_encode(bytes_digest)
67
+ return self.new_sub_action(new_name)
68
+
69
+
70
+ @dataclass(frozen=True, kw_only=True)
71
+ class RawDataPath:
72
+ """
73
+ A class representing the raw data path for a task. This is used to store the raw data for the task execution and
74
+ also get mutations on the path.
75
+ """
76
+
77
+ path: str
78
+
79
+ @classmethod
80
+ def from_local_folder(cls, local_folder: str | pathlib.Path | None = None) -> RawDataPath:
81
+ """
82
+ Create a new context attribute object, with local path given. Will be created if it doesn't exist.
83
+ :return: Path to the temporary directory
84
+ """
85
+ match local_folder:
86
+ case pathlib.Path():
87
+ local_folder.mkdir(parents=True, exist_ok=True)
88
+ return RawDataPath(path=str(local_folder))
89
+ case None:
90
+ # Create a temporary directory for data storage
91
+ p = tempfile.mkdtemp()
92
+ logger.debug(f"Creating temporary directory for data storage: {p}")
93
+ return RawDataPath(path=p)
94
+ case str():
95
+ return RawDataPath(path=local_folder)
96
+ case _:
97
+ raise ValueError(f"Invalid local path {local_folder}")
98
+
99
+ def get_random_remote_path(self, file_name: Optional[str] = None) -> str:
100
+ """
101
+ Returns a random path for uploading a file/directory to.
102
+
103
+ :param file_name: If given, will be joined after a randomly generated portion.
104
+ :return:
105
+ """
106
+ import random
107
+ from uuid import UUID
108
+
109
+ import fsspec
110
+ from fsspec.utils import get_protocol
111
+
112
+ random_string = UUID(int=random.getrandbits(128)).hex
113
+ file_prefix = self.path
114
+
115
+ protocol = get_protocol(file_prefix)
116
+ if "file" in protocol:
117
+ local_path = pathlib.Path(file_prefix) / random_string
118
+ if file_name:
119
+ # Only if file name is given do we create the parent, because it may be needed as a folder otherwise
120
+ local_path = local_path / file_name
121
+ if not local_path.exists():
122
+ local_path.parent.mkdir(exist_ok=True, parents=True)
123
+ local_path.touch()
124
+ return str(local_path.absolute())
125
+
126
+ fs = fsspec.filesystem(protocol)
127
+ if file_prefix.endswith(fs.sep):
128
+ file_prefix = file_prefix[:-1]
129
+ remote_path = fs.sep.join([file_prefix, random_string])
130
+ if file_name:
131
+ remote_path = fs.sep.join([remote_path, file_name])
132
+ return remote_path
133
+
134
+
135
+ @dataclass(frozen=True)
136
+ class GroupData:
137
+ name: str
138
+
139
+
140
+ @dataclass(frozen=True, kw_only=True)
141
+ class TaskContext:
142
+ """
143
+ A context class to hold the current task executions context.
144
+ This can be used to access various contextual parameters in the task execution by the user.
145
+
146
+ :param action: The action ID of the current execution. This is always set, within a run.
147
+ :param version: The version of the executed task. This is set when the task is executed by an action and will be
148
+ set on all sub-actions.
149
+ """
150
+
151
+ action: ActionID
152
+ version: str
153
+ raw_data_path: RawDataPath
154
+ output_path: str
155
+ report: Report | None = None # This field is available if reports are enabled
156
+ group_data: GroupData | None = None
157
+ checkpoints: Checkpoints | None = None
158
+ code_bundle: CodeBundle | None = None
159
+ compiled_image_cache: ImageCache | None = None
160
+ data: Dict[str, Any] = field(default_factory=dict)
161
+
162
+ def replace(self, **kwargs) -> TaskContext:
163
+ if "data" in kwargs:
164
+ rec_data = kwargs.pop("data")
165
+ if rec_data is None:
166
+ return replace(self, **kwargs)
167
+ data = {}
168
+ if self.data is not None:
169
+ data = self.data.copy()
170
+ data.update(rec_data)
171
+ kwargs.update({"data": data})
172
+ return replace(self, **kwargs)
173
+
174
+ def __getitem__(self, key: str) -> Optional[Any]:
175
+ return self.data.get(key)
176
+
177
+
178
+ @dataclass(frozen=True, kw_only=True)
179
+ class CodeBundle:
180
+ """
181
+ A class representing a code bundle for a task. This is used to package the code and the inflation path.
182
+ The code bundle computes the version of the code using the hash of the code.
183
+
184
+ :param computed_version: The version of the code bundle. This is the hash of the code.
185
+ :param destination: The destination path for the code bundle to be inflated to.
186
+ :param tgz: Optional path to the tgz file.
187
+ :param pkl: Optional path to the pkl file.
188
+ :param downloaded_path: The path to the downloaded code bundle. This is only available during runtime, when
189
+ the code bundle has been downloaded and inflated.
190
+ """
191
+
192
+ computed_version: str
193
+ destination: str = "."
194
+ tgz: str | None = None
195
+ pkl: str | None = None
196
+ downloaded_path: pathlib.Path | None = None
197
+
198
+ # runtime_dependencies: Tuple[str, ...] = field(default_factory=tuple) In the future if we want we could add this
199
+ # but this messes up actors, spark etc
200
+
201
+ def __post_init__(self):
202
+ if self.tgz is None and self.pkl is None:
203
+ raise ValueError("Either tgz or pkl must be provided")
204
+
205
+ def with_downloaded_path(self, path: pathlib.Path) -> CodeBundle:
206
+ """
207
+ Create a new CodeBundle with the given downloaded path.
208
+ """
209
+ return replace(self, downloaded_path=path)
210
+
211
+
212
+ @dataclass(frozen=True)
213
+ class Checkpoints:
214
+ """
215
+ A class representing the checkpoints for a task. This is used to store the checkpoints for the task execution.
216
+ """
217
+
218
+ prev_checkpoint_path: str | None
219
+ checkpoint_path: str | None
220
+
221
+
222
+ @dataclass(frozen=True)
223
+ class NativeInterface:
224
+ """
225
+ A class representing the native interface for a task. This is used to interact with the task and its execution
226
+ context.
227
+ """
228
+
229
+ inputs: Dict[str, Tuple[Type, Any]]
230
+ outputs: Dict[str, Type]
231
+ docstring: Optional[Docstring] = field(default=(None,))
232
+
233
+ @classmethod
234
+ def from_callable(cls, func: Callable) -> NativeInterface:
235
+ """
236
+ Extract the native interface from the given function. This is used to create a native interface for the task.
237
+ """
238
+ sig = inspect.signature(func)
239
+
240
+ # Extract parameter details (name, type, default value)
241
+ param_info = {name: (param.annotation, param.default) for name, param in sig.parameters.items()}
242
+
243
+ # Get return type
244
+ outputs = extract_return_annotation(sig.return_annotation)
245
+ return cls(inputs=param_info, outputs=outputs)
246
+
247
+ def convert_to_kwargs(self, *args, **kwargs) -> Dict[str, Any]:
248
+ """
249
+ Convert the given arguments to keyword arguments based on the native interface. This is used to convert the
250
+ arguments to the correct types for the task execution.
251
+ """
252
+ # Convert positional arguments to keyword arguments
253
+ if len(args) > len(self.inputs):
254
+ raise ValueError(f"Too many positional arguments provided, inputs {self.inputs.keys()}, args {len(args)}")
255
+ for arg, input_name in zip(args, self.inputs.keys()):
256
+ kwargs[input_name] = arg
257
+ return kwargs
258
+
259
+ def get_input_types(self) -> Dict[str, Type]:
260
+ """
261
+ Get the input types for the task. This is used to get the types of the inputs for the task execution.
262
+ """
263
+ return {k: v[0] for k, v in self.inputs.items()}
264
+
265
+
266
+ @dataclass
267
+ class SerializationContext:
268
+ """
269
+ This object holds serialization time contextual information, that can be used when serializing the task and
270
+ various parameters of a tasktemplate. This is only available when the task is being serialized and can be
271
+ during a deployment or runtime.
272
+
273
+ :param version: The version of the task
274
+ :param code_bundle: The code bundle for the task. This is used to package the code and the inflation path.
275
+ :param input_path: The path to the inputs for the task. This is used to determine where the inputs will be located
276
+ :param output_path: The path to the outputs for the task. This is used to determine where the outputs will be
277
+ located
278
+ """
279
+
280
+ version: str
281
+ project: str | None = None
282
+ domain: str | None = None
283
+ org: str | None = None
284
+ code_bundle: Optional[CodeBundle] = None
285
+ input_path: str = "{{.input}}"
286
+ output_path: str = "{{.outputPrefix}}"
287
+ _entrypoint_path: str = field(default="_bin/runtime.py", init=False)
288
+ image_cache: ImageCache | None = None
289
+
290
+ def get_entrypoint_path(self, interpreter_path: str) -> str:
291
+ """
292
+ Get the entrypoint path for the task. This is used to determine the entrypoint for the task execution.
293
+ :param interpreter_path: The path to the interpreter (python)
294
+ """
295
+ return os.path.join(os.path.dirname(os.path.dirname(interpreter_path)), self._entrypoint_path)
union/_deploy.py ADDED
@@ -0,0 +1,185 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
6
+
7
+ import rich.repr
8
+
9
+ from ._api_commons import syncer
10
+ from ._datastructures import SerializationContext
11
+ from ._environment import Environment
12
+ from ._image import Image
13
+ from ._initialize import get_client, get_common_config, requires_client, requires_initialization
14
+ from ._logging import logger
15
+ from ._task import TaskTemplate
16
+ from ._task_environment import TaskEnvironment
17
+
18
+ if TYPE_CHECKING:
19
+ from union._protos.workflow import task_definition_pb2
20
+
21
+ from ._code_bundle import CopyFiles
22
+ from ._internal.imagebuild.image_builder import ImageCache
23
+
24
+
25
+ @rich.repr.auto
26
+ @dataclass
27
+ class DeploymentPlan:
28
+ envs: Dict[str, Environment]
29
+ version: Optional[str] = None
30
+
31
+
32
+ @rich.repr.auto
33
+ @dataclass
34
+ class Deployment:
35
+ envs: Dict[str, Environment]
36
+ deployed_tasks: List[task_definition_pb2.TaskSpec] | None = None
37
+
38
+
39
+ @requires_client
40
+ async def _deploy_task(
41
+ task: TaskTemplate, serialization_context: SerializationContext, dryrun: bool = False
42
+ ) -> task_definition_pb2.TaskSpec:
43
+ """
44
+ Deploy the given task.
45
+ """
46
+ from ._internal.runtime.task_serde import translate_task_to_wire
47
+ from ._protos.workflow import task_definition_pb2, task_service_pb2
48
+
49
+ image_uri = task.image.uri if isinstance(task.image, Image) else task.image
50
+
51
+ spec = translate_task_to_wire(task, serialization_context)
52
+ if dryrun:
53
+ return spec
54
+ logger.info(f"Deploying task {task.name}, with image {image_uri} and {serialization_context.version=} spec: {spec}")
55
+ cfg = get_common_config()
56
+ task_id = task_definition_pb2.TaskIdentifier(
57
+ org=cfg.org,
58
+ project=cfg.project,
59
+ domain=cfg.domain,
60
+ version=serialization_context.version,
61
+ name=spec.task_template.id.name,
62
+ )
63
+
64
+ resp = await get_client().task_service.DeployTask(task_service_pb2.DeployTaskRequest(task_id=task_id, spec=spec))
65
+ logger.info(f"Deployed task {task.name}, {resp}")
66
+ return spec
67
+
68
+
69
+ async def _build_image_bg(env_name: str, image: Image) -> Tuple[str, str]:
70
+ """
71
+ Build the image in the background and return the environment name and the built image.
72
+ """
73
+ from ._build import build
74
+
75
+ logger.info(f"Building image {image.name} for environment {env_name}")
76
+ return env_name, await build.aio(image)
77
+
78
+
79
+ async def build_images(deployment: DeploymentPlan) -> ImageCache:
80
+ """
81
+ Build the images for the given deployment plan and update the environment with the built image.
82
+ """
83
+ from ._internal.imagebuild.image_builder import ImageCache
84
+
85
+ images = []
86
+ image_identifier_map = {}
87
+ for env_name, env in deployment.envs.items():
88
+ if not isinstance(env.image, str):
89
+ logger.info(f"Building Image for environment {env_name}, image: {env.image}")
90
+ images.append(_build_image_bg(env_name, env.image))
91
+
92
+ elif env.image == "auto" and "auto" not in image_identifier_map:
93
+ auto_image = Image.auto()
94
+ image_identifier_map["auto"] = auto_image.uri
95
+ final_images = await asyncio.gather(*images)
96
+
97
+ for env_name, image_uri in final_images:
98
+ logger.info(f"Built Image for environment {env_name}, image: {image_uri}")
99
+ env = deployment.envs[env_name]
100
+ image_identifier_map[env.image.identifier] = env.image.uri
101
+
102
+ return ImageCache(image_lookup=image_identifier_map)
103
+
104
+
105
+ @requires_initialization
106
+ async def apply(deployment: DeploymentPlan, copy_style: CopyFiles, dryrun: bool = False) -> Deployment:
107
+ from ._code_bundle import build_code_bundle
108
+
109
+ cfg = get_common_config()
110
+ image_cache = await build_images(deployment)
111
+ if copy_style == "none":
112
+ code_bundle = None
113
+ assert deployment.version is not None, "Version must be set when copy_style is none"
114
+ else:
115
+ code_bundle = await build_code_bundle(from_dir=cfg.root_dir, dryrun=dryrun, copy_style=copy_style)
116
+ deployment.version = code_bundle.computed_version
117
+
118
+ sc = SerializationContext(
119
+ code_bundle=code_bundle,
120
+ version=deployment.version or code_bundle.computed_version,
121
+ image_cache=image_cache,
122
+ )
123
+
124
+ tasks = []
125
+ for env_name, env in deployment.envs.items():
126
+ logger.info(f"Deploying environment {env_name}")
127
+ if isinstance(env, TaskEnvironment):
128
+ for task in env.tasks.values():
129
+ tasks.append(_deploy_task(task, dryrun=dryrun, serialization_context=sc))
130
+ return Deployment(envs=deployment.envs, deployed_tasks=await asyncio.gather(*tasks))
131
+
132
+
133
+ def _recursive_discover(
134
+ planned_envs: Dict[str, Environment], envs: Environment | List[Environment]
135
+ ) -> Dict[str, Environment]:
136
+ """
137
+ Recursively deploy the environment and its dependencies, if not already deployed (present in env_tasks) and
138
+ return the updated env_tasks.
139
+ """
140
+ if isinstance(envs, Environment):
141
+ envs = [envs]
142
+ for env in envs:
143
+ # Skip if the environment is already planned
144
+ if env.name in planned_envs:
145
+ continue
146
+ # Recursively discover dependent environments
147
+ for dependent_env in env.env_dep_hints:
148
+ _recursive_discover(planned_envs, dependent_env)
149
+ # Add the environment to the existing envs
150
+ planned_envs[env.name] = env
151
+ return planned_envs
152
+
153
+
154
+ def plan_deploy(*envs: Environment, version: Optional[str] = None) -> DeploymentPlan:
155
+ if envs is None:
156
+ return DeploymentPlan({})
157
+ planned_envs = _recursive_discover({}, *envs)
158
+ return DeploymentPlan(planned_envs, version=version)
159
+
160
+
161
+ @syncer.wrap
162
+ async def deploy(
163
+ *envs: Environment,
164
+ dryrun: bool = False,
165
+ version: str | None = None,
166
+ interactive_mode: bool | None = None,
167
+ copy_style: CopyFiles = "loaded_modules",
168
+ ) -> Deployment:
169
+ """
170
+ Deploy the given environment or list of environments.
171
+ :param envs: Environment or list of environments to deploy.
172
+ :param dryrun: dryrun mode, if True, the deployment will not be applied to the control plane.
173
+ :param version: version of the deployment, if None, the version will be computed from the code bundle.
174
+ TODO: Support for interactive_mode
175
+ :param interactive_mode: Optional, can be forced to True or False.
176
+ If not provided, it will be set based on the current environment. For example Jupyter notebooks are considered
177
+ interactive mode, while scripts are not. This is used to determine how the code bundle is created.
178
+ :param copy_style: Copy style to use when running the task
179
+
180
+ :return: Deployment object containing the deployed environments and tasks.
181
+ """
182
+ if interactive_mode:
183
+ raise NotImplementedError("Interactive mode not yet implemented for deployment")
184
+ deployment = plan_deploy(*envs, version=version)
185
+ return await apply(deployment, copy_style=copy_style, dryrun=dryrun)
union/_doc.py ADDED
@@ -0,0 +1,29 @@
1
+ import inspect
2
+ from dataclasses import dataclass
3
+ from typing import Callable
4
+
5
+
6
+ @dataclass
7
+ class Documentation:
8
+ """
9
+ This class is used to store the documentation of a task.
10
+
11
+ It can be set explicitly or extracted from the docstring of the task.
12
+ """
13
+
14
+ description: str
15
+
16
+ def __help__str__(self):
17
+ return self.description
18
+
19
+
20
+ def extract_docstring(func: Callable) -> Documentation:
21
+ """
22
+ Extracts the description from a docstring.
23
+ """
24
+ if not func:
25
+ return Documentation(description="")
26
+ docstring = inspect.getdoc(func)
27
+ if not docstring:
28
+ return Documentation(description="")
29
+ return Documentation(description=docstring)
union/_docstring.py ADDED
@@ -0,0 +1,26 @@
1
+ from typing import Callable, Dict, Optional
2
+
3
+
4
+ class Docstring(object):
5
+ def __init__(self, docstring: Optional[str] = None, callable_: Optional[Callable] = None):
6
+ if docstring is not None:
7
+ # from docstring_parser import parse
8
+ self._parsed_docstring = "" # parse(docstring)
9
+ else:
10
+ self._parsed_docstring = "" # parse(callable_.__doc__)
11
+
12
+ @property
13
+ def input_descriptions(self) -> Dict[str, str]:
14
+ return {p.arg_name: p.description for p in self._parsed_docstring.params}
15
+
16
+ @property
17
+ def output_descriptions(self) -> Dict[str, str]:
18
+ return {p.return_name: p.description for p in self._parsed_docstring.many_returns}
19
+
20
+ @property
21
+ def short_description(self) -> Optional[str]:
22
+ return self._parsed_docstring.short_description
23
+
24
+ @property
25
+ def long_description(self) -> Optional[str]:
26
+ return self._parsed_docstring.long_description
union/_environment.py ADDED
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union
5
+
6
+ import rich.repr
7
+
8
+ from union._secret import SecretRequest
9
+
10
+ from ._image import Image
11
+ from ._resources import Resources
12
+
13
+ if TYPE_CHECKING:
14
+ from kubernetes.client import V1PodTemplate
15
+
16
+
17
+ @rich.repr.auto
18
+ @dataclass(init=True, repr=True)
19
+ class Environment:
20
+ """
21
+ :param name: Name of the environment
22
+ :param image: Docker image to use for the environment. If set to "auto", will use the default image.
23
+ :param resources: Resources to allocate for the environment.
24
+ :param env: Environment variables to set for the environment.
25
+ :param secrets: Secrets to inject into the environment.
26
+ :param env_dep_hints: Environment dependencies to hint, so when you deploy the environment, the dependencies are
27
+ also deployed. This is useful when you have a set of environments that depend on each other.
28
+ """
29
+
30
+ name: str
31
+ env_dep_hints: List[Environment] = field(default_factory=list)
32
+ pod_template: Optional[Union[str, "V1PodTemplate"]] = None
33
+ description: Optional[str] = None
34
+ secrets: Optional[SecretRequest] = None
35
+ env: Optional[Dict[str, str]] = None
36
+ resources: Optional[Resources] = None
37
+ image: Union[str, Image, Literal["auto"]] = "auto"
38
+
39
+ def add_dependency(self, *env: Environment):
40
+ """
41
+ Add a dependency to the environment.
42
+ """
43
+ self.env_dep_hints.extend(env)
union/_group.py ADDED
@@ -0,0 +1,31 @@
1
+ from contextlib import contextmanager
2
+
3
+ from ._context import internal_ctx
4
+ from ._datastructures import GroupData
5
+
6
+
7
+ @contextmanager
8
+ def group(name: str):
9
+ """
10
+ Create a new group with the given name. The method is intended to be used as a context manager.
11
+
12
+ Example:
13
+ ```python
14
+ @task
15
+ async def my_task():
16
+ ...
17
+ with group("my_group"):
18
+ t1(x,y) # tasks in this block will be grouped under "my_group"
19
+ ...
20
+ ```
21
+
22
+ :param name: The name of the group
23
+ """
24
+ ctx = internal_ctx()
25
+ if ctx.data.task_context is None:
26
+ yield
27
+ return
28
+ tctx = ctx.data.task_context
29
+ new_tctx = tctx.replace(group_data=GroupData(name))
30
+ with ctx.replace_task_context(new_tctx):
31
+ yield
union/_hash.py ADDED
@@ -0,0 +1,23 @@
1
+ from typing import Callable, Generic, TypeVar
2
+
3
+ T = TypeVar("T")
4
+
5
+
6
+ class HashOnReferenceMixin(object):
7
+ def __hash__(self):
8
+ return hash(id(self))
9
+
10
+
11
+ class HashMethod(Generic[T]):
12
+ """
13
+ Flyte-specific object used to wrap the hash function for a specific type
14
+ """
15
+
16
+ def __init__(self, function: Callable[[T], str]):
17
+ self._function = function
18
+
19
+ def calculate(self, obj: T) -> str:
20
+ """
21
+ Calculate hash for `obj`.
22
+ """
23
+ return self._function(obj)