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
union/_utils/asyn.py ADDED
@@ -0,0 +1,119 @@
1
+ """Manages an async event loop on another thread. Developers should only require to call
2
+ sync to use the managed loop:
3
+
4
+ from flytekit.tools.asyn import run_sync
5
+
6
+ async def async_add(a: int, b: int) -> int:
7
+ return a + b
8
+
9
+ result = run_sync(async_add, a=10, b=12)
10
+ """
11
+
12
+ import asyncio
13
+ import atexit
14
+ import functools
15
+ import os
16
+ import threading
17
+ from contextlib import contextmanager
18
+ from typing import Any, Awaitable, Callable, TypeVar
19
+
20
+ from typing_extensions import ParamSpec
21
+
22
+ from union._logging import logger
23
+
24
+ T = TypeVar("T")
25
+
26
+ P = ParamSpec("P")
27
+
28
+
29
+ @contextmanager
30
+ def _selector_policy():
31
+ original_policy = asyncio.get_event_loop_policy()
32
+ try:
33
+ if os.name == "nt" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"):
34
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
35
+
36
+ yield
37
+ finally:
38
+ asyncio.set_event_loop_policy(original_policy)
39
+
40
+
41
+ class _TaskRunner:
42
+ """A task runner that runs an asyncio event loop on a background thread."""
43
+
44
+ def __init__(self) -> None:
45
+ self.__loop: asyncio.AbstractEventLoop | None = None
46
+ self.__runner_thread: threading.Thread | None = None
47
+ self.__lock = threading.Lock()
48
+ atexit.register(self._close)
49
+
50
+ def _close(self) -> None:
51
+ if self.__loop:
52
+ self.__loop.stop()
53
+
54
+ def _execute(self) -> None:
55
+ loop = self.__loop
56
+ assert loop is not None
57
+ try:
58
+ loop.run_forever()
59
+ finally:
60
+ loop.close()
61
+
62
+ def get_exc_handler(self):
63
+ def exc_handler(loop, context):
64
+ logger.error(
65
+ f"Taskrunner for {self.__runner_thread.name if self.__runner_thread else 'no thread'} caught"
66
+ f" exception in {loop}: {context}"
67
+ )
68
+
69
+ return exc_handler
70
+
71
+ def run(self, coro: Any) -> Any:
72
+ """Synchronously run a coroutine on a background thread."""
73
+ name = f"{threading.current_thread().name} : loop-runner"
74
+ with self.__lock:
75
+ if self.__loop is None:
76
+ with _selector_policy():
77
+ self.__loop = asyncio.new_event_loop()
78
+
79
+ exc_handler = self.get_exc_handler()
80
+ self.__loop.set_exception_handler(exc_handler)
81
+ self.__runner_thread = threading.Thread(target=self._execute, daemon=True, name=name)
82
+ self.__runner_thread.start()
83
+ fut = asyncio.run_coroutine_threadsafe(coro, self.__loop)
84
+
85
+ res = fut.result(None)
86
+
87
+ return res
88
+
89
+
90
+ class _AsyncLoopManager:
91
+ def __init__(self):
92
+ self._runner_map: dict[str, _TaskRunner] = {}
93
+
94
+ def run_sync(self, coro_func: Callable[..., Awaitable[T]], *args, **kwargs) -> T:
95
+ """
96
+ This should be called from synchronous functions to run an async function.
97
+ """
98
+ name = threading.current_thread().name + f"PID:{os.getpid()}"
99
+ coro = coro_func(*args, **kwargs)
100
+ if name not in self._runner_map:
101
+ if len(self._runner_map) > 500:
102
+ logger.warning(
103
+ "More than 500 event loop runners created!!! This could be a case of runaway recursion..."
104
+ )
105
+ self._runner_map[name] = _TaskRunner()
106
+ return self._runner_map[name].run(coro)
107
+
108
+ def synced(self, coro_func: Callable[P, Awaitable[T]]) -> Callable[P, T]:
109
+ """Make loop run coroutine until it returns. Runs in other thread"""
110
+
111
+ @functools.wraps(coro_func)
112
+ def wrapped(*args: Any, **kwargs: Any) -> T:
113
+ return self.run_sync(coro_func, *args, **kwargs)
114
+
115
+ return wrapped
116
+
117
+
118
+ loop_manager = _AsyncLoopManager()
119
+ run_sync = loop_manager.run_sync
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import os
5
+ import pathlib
6
+ import stat
7
+ from pathlib import Path
8
+ from typing import List, Optional, Union
9
+
10
+ from union._logging import logger
11
+
12
+
13
+ def filehash_update(path: pathlib.Path, hasher: hashlib._Hash) -> None:
14
+ blocksize = 65536
15
+ with open(path, "rb") as f:
16
+ bytes = f.read(blocksize)
17
+ while bytes:
18
+ hasher.update(bytes)
19
+ bytes = f.read(blocksize)
20
+
21
+
22
+ def _pathhash_update(path: Union[os.PathLike, str], hasher: hashlib._Hash) -> None:
23
+ path_list = path.split(os.sep)
24
+ hasher.update("".join(path_list).encode("utf-8"))
25
+
26
+
27
+ def update_hasher_for_source(
28
+ source: Union[os.PathLike, List[os.PathLike]], hasher: hashlib._Hash, filter: Optional[callable] = None
29
+ ) -> str:
30
+ """
31
+ Walks the entirety of the source dir to compute a deterministic md5 hex digest of the dir contents.
32
+ :param os.PathLike source:
33
+ :param callable filter:
34
+ :return Text:
35
+ """
36
+
37
+ def compute_digest_for_file(path: os.PathLike, rel_path: os.PathLike) -> None:
38
+ # Only consider files that exist (e.g. disregard symlinks that point to non-existent files)
39
+ if not os.path.exists(path):
40
+ logger.info(f"Skipping non-existent file {path}")
41
+ return
42
+
43
+ # Skip socket files
44
+ if stat.S_ISSOCK(os.stat(path).st_mode):
45
+ logger.info(f"Skip socket file {path}")
46
+ return
47
+
48
+ if filter:
49
+ if filter(rel_path):
50
+ return
51
+
52
+ filehash_update(Path(path), hasher)
53
+ _pathhash_update(rel_path, hasher)
54
+
55
+ def compute_digest_for_dir(source: os.PathLike) -> None:
56
+ for root, _, files in os.walk(source, topdown=True):
57
+ files.sort()
58
+
59
+ for fname in files:
60
+ abspath = os.path.join(root, fname)
61
+ relpath = os.path.relpath(abspath, source)
62
+ compute_digest_for_file(abspath, relpath)
63
+
64
+ if isinstance(source, list):
65
+ for src in source:
66
+ if os.path.isdir(src):
67
+ compute_digest_for_dir(src)
68
+ else:
69
+ compute_digest_for_file(src, os.path.basename(src))
70
+ else:
71
+ compute_digest_for_dir(source)
@@ -0,0 +1,46 @@
1
+ import os
2
+ import string
3
+ import typing
4
+ from pathlib import Path
5
+
6
+
7
+ def load_proto_from_file(pb2_type, path):
8
+ with open(path, "rb") as reader:
9
+ out = pb2_type()
10
+ out.ParseFromString(reader.read())
11
+ return out
12
+
13
+
14
+ def write_proto_to_file(proto, path):
15
+ Path(os.path.dirname(path)).mkdir(parents=True, exist_ok=True)
16
+ with open(path, "wb") as writer:
17
+ writer.write(proto.SerializeToString())
18
+
19
+
20
+ def str2bool(value: typing.Optional[str]) -> bool:
21
+ """
22
+ Convert a string to a boolean. This is useful for parsing environment variables.
23
+ :param value: The string to convert to a boolean
24
+ :return: the boolean value
25
+ """
26
+ if value is None:
27
+ return False
28
+ return value.lower() in ("true", "t", "1")
29
+
30
+
31
+ BASE62_ALPHABET = string.digits + string.ascii_letters # 0-9 + A-Z + a-z (62 characters)
32
+
33
+
34
+ def base62_encode(byte_data: bytes) -> str:
35
+ # Convert bytes to a big integer
36
+ num = int.from_bytes(byte_data, byteorder="big")
37
+
38
+ # Convert integer to base62 string
39
+ if num == 0:
40
+ return BASE62_ALPHABET[0]
41
+
42
+ base62 = []
43
+ while num:
44
+ num, rem = divmod(num, 62)
45
+ base62.append(BASE62_ALPHABET[rem])
46
+ return "".join(reversed(base62))
@@ -0,0 +1,54 @@
1
+ import importlib.util
2
+ import sys
3
+ import types
4
+
5
+
6
+ class _LazyModule(types.ModuleType):
7
+ """
8
+ `lazy_module` returns an instance of this class if the module is not found in the python environment.
9
+ """
10
+
11
+ def __init__(self, module_name: str):
12
+ super().__init__(module_name)
13
+ self._module_name = module_name
14
+
15
+ def __getattribute__(self, attr):
16
+ raise ImportError(f"Module {object.__getattribute__(self, '_module_name')} is not yet installed.")
17
+
18
+
19
+ def is_imported(module_name):
20
+ """
21
+ This function is used to check if a module has been imported by the regular import.
22
+ Return false if module is lazy imported and not used yet.
23
+ """
24
+ return (
25
+ module_name in sys.modules
26
+ and object.__getattribute__(lazy_module(module_name), "__class__").__name__ != "_LazyModule"
27
+ )
28
+
29
+
30
+ def lazy_module(fullname):
31
+ """
32
+ This function is used to lazily import modules. It is used in the following way:
33
+ .. code-block:: python
34
+ from flytekit.lazy_import import lazy_module
35
+ sklearn = lazy_module("sklearn")
36
+ sklearn.svm.SVC()
37
+ :param Text fullname: The full name of the module to import
38
+ """
39
+ if fullname in sys.modules:
40
+ return sys.modules[fullname]
41
+ # https://docs.python.org/3/library/importlib.html#implementing-lazy-imports
42
+ spec = importlib.util.find_spec(fullname)
43
+ if spec is None or spec.loader is None:
44
+ # Return a lazy module if the module is not found in the python environment,
45
+ # so that we can raise a proper error when the user tries to access an attribute in the module.
46
+ # The reason to do this is because importlib.util.LazyLoader still requires
47
+ # the module to be installed even if you don't use it.
48
+ return _LazyModule(fullname)
49
+ loader = importlib.util.LazyLoader(spec.loader)
50
+ spec.loader = loader
51
+ module = importlib.util.module_from_spec(spec)
52
+ sys.modules[fullname] = module
53
+ loader.exec_module(module)
54
+ return module
@@ -0,0 +1,49 @@
1
+ import pathlib
2
+ import re
3
+ from dataclasses import dataclass, field
4
+ from typing import Dict, List, Optional
5
+
6
+ import toml
7
+
8
+
9
+ @dataclass
10
+ class ToolUVConfig:
11
+ exclude_newer: Optional[str] = None
12
+
13
+
14
+ @dataclass
15
+ class UVScriptMetadata:
16
+ requires_python: Optional[str] = None
17
+ dependencies: List[str] = field(default_factory=list)
18
+ tool: Optional[Dict[str, ToolUVConfig]] = None
19
+
20
+
21
+ def _extract_uv_metadata_block(text: str) -> str | None:
22
+ pattern = re.compile(r"# /// script\s*(.*?)# ///", re.DOTALL)
23
+ match = pattern.search(text)
24
+ if not match:
25
+ return None
26
+ lines = [line.lstrip("# ").rstrip() for line in match.group(1).splitlines()]
27
+ return "\n".join(lines)
28
+
29
+
30
+ def parse_uv_script_file(path: pathlib.Path) -> UVScriptMetadata:
31
+ if not path.exists() or not path.is_file():
32
+ raise FileNotFoundError(f"File not found: {path}")
33
+
34
+ text = path.read_text(encoding="utf-8")
35
+ raw_header = _extract_uv_metadata_block(text)
36
+ if raw_header is None:
37
+ raise ValueError("No uv metadata block found")
38
+
39
+ try:
40
+ data = toml.loads(raw_header)
41
+ except toml.TomlDecodeError as e:
42
+ raise ValueError(f"Invalid TOML in metadata block: {e}")
43
+
44
+ tool_data = data.get("tool", {}).get("uv", {})
45
+ return UVScriptMetadata(
46
+ requires_python=data.get("requires-python"),
47
+ dependencies=data.get("dependencies", []),
48
+ tool={"uv": ToolUVConfig(exclude_newer=tool_data.get("exclude-newer"))} if tool_data else None,
49
+ )
union/_version.py ADDED
@@ -0,0 +1,21 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
6
+ TYPE_CHECKING = False
7
+ if TYPE_CHECKING:
8
+ from typing import Tuple
9
+ from typing import Union
10
+
11
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
12
+ else:
13
+ VERSION_TUPLE = object
14
+
15
+ version: str
16
+ __version__: str
17
+ __version_tuple__: VERSION_TUPLE
18
+ version_tuple: VERSION_TUPLE
19
+
20
+ __version__ = version = '0.1.dev160+g7ce653a.d20250515'
21
+ __version_tuple__ = version_tuple = (0, 1, 'dev160', 'g7ce653a.d20250515')
File without changes
union/errors.py ADDED
@@ -0,0 +1,128 @@
1
+ """
2
+ Exceptions raised by Union.
3
+
4
+ These errors are raised when the underlying task execution fails, either because of a user error, system error or an
5
+ unknown error.
6
+ """
7
+
8
+ from typing import Literal
9
+
10
+ ErrorKind = Literal["system", "unknown", "user"]
11
+
12
+
13
+ class RuntimeError(RuntimeError):
14
+ """
15
+ Base class for all Union runtime errors. These errors are raised when the underlying task execution fails, either
16
+ because of a user error, system error or an unknown error.
17
+ """
18
+
19
+ def __init__(self, code: str, kind: ErrorKind, root_cause_message: str, worker: str | None = None):
20
+ super().__init__(root_cause_message)
21
+ self.code = code
22
+ self.kind = kind
23
+ self.worker = worker
24
+
25
+
26
+ class InitializationError(RuntimeError):
27
+ """
28
+ This error is raised when the Union system is tried to access without being initialized.
29
+ """
30
+
31
+
32
+ class RuntimeSystemError(RuntimeError):
33
+ """
34
+ This error is raised when the underlying task execution fails because of a system error. This could be a bug in the
35
+ Union system or a bug in the user's code.
36
+ """
37
+
38
+ def __init__(self, code: str, message: str, worker: str | None = None):
39
+ super().__init__(code, "system", message, worker)
40
+
41
+
42
+ class UnionRpcError(RuntimeSystemError):
43
+ """
44
+ This error is raised when communication with the Union server fails.
45
+ """
46
+
47
+
48
+ class RuntimeUserError(RuntimeError):
49
+ """
50
+ This error is raised when the underlying task execution fails because of an error in the user's code.
51
+ """
52
+
53
+ def __init__(self, code: str, message: str, worker: str | None = None):
54
+ super().__init__(code, "user", message, worker)
55
+
56
+
57
+ class RuntimeUnknownError(RuntimeError):
58
+ """
59
+ This error is raised when the underlying task execution fails because of an unknown error.
60
+ """
61
+
62
+ def __init__(self, code: str, message: str, worker: str | None = None):
63
+ super().__init__(code, "unknown", message, worker)
64
+
65
+
66
+ class OOMError(RuntimeUserError):
67
+ """
68
+ This error is raised when the underlying task execution fails because of an out-of-memory error.
69
+ """
70
+
71
+
72
+ class TaskInterruptedError(RuntimeUserError):
73
+ """
74
+ This error is raised when the underlying task execution is interrupted.
75
+ """
76
+
77
+
78
+ class PrimaryContainerNotFoundError(RuntimeUserError):
79
+ """
80
+ This error is raised when the primary container is not found.
81
+ """
82
+
83
+
84
+ class TaskTimeoutError(RuntimeUserError):
85
+ """
86
+ This error is raised when the underlying task execution runs for longer than the specified timeout.
87
+ """
88
+
89
+
90
+ class RetriesExhaustedError(RuntimeUserError):
91
+ """
92
+ This error is raised when the underlying task execution fails after all retries have been exhausted.
93
+ """
94
+
95
+
96
+ class InvalidImageNameError(RuntimeUserError):
97
+ """
98
+ This error is raised when the image name is invalid.
99
+ """
100
+
101
+
102
+ class ImagePullBackOffError(RuntimeUserError):
103
+ """
104
+ This error is raised when the image cannot be pulled.
105
+ """
106
+
107
+
108
+ class CustomError(RuntimeUserError):
109
+ """
110
+ This error is raised when the user raises a custom error.
111
+ """
112
+
113
+ def __init__(self, code: str, message: str):
114
+ super().__init__(code, message, "user")
115
+
116
+ @classmethod
117
+ def from_exception(cls, e: Exception):
118
+ """
119
+ Create a CustomError from an exception. The exception's class name is used as the error code and the exception
120
+ message is used as the error message.
121
+ """
122
+ return cls(e.__class__.__name__, str(e))
123
+
124
+
125
+ class NotInTaskContextError(RuntimeUserError):
126
+ """
127
+ This error is raised when the user tries to access the task context outside of a task.
128
+ """
@@ -0,0 +1,5 @@
1
+ from ._container import ContainerTask
2
+
3
+ __all__ = [
4
+ "ContainerTask",
5
+ ]