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
@@ -1,4 +1,3 @@
1
- import asyncio
2
1
  import dataclasses
3
2
  import datetime
4
3
  import enum
@@ -7,6 +6,7 @@ import importlib.util
7
6
  import json
8
7
  import os
9
8
  import pathlib
9
+ import re
10
10
  import sys
11
11
  import typing
12
12
  import typing as t
@@ -14,24 +14,16 @@ from typing import get_args
14
14
 
15
15
  import rich_click as click
16
16
  import yaml
17
+ from click import Parameter
18
+ from flyteidl.core.interface_pb2 import Variable
17
19
  from flyteidl.core.literals_pb2 import Literal
18
20
  from flyteidl.core.types_pb2 import BlobType, LiteralType, SimpleType
21
+ from google.protobuf.json_format import MessageToDict
22
+ from mashumaro.codecs.json import JSONEncoder
19
23
 
20
- from union._logging import logger
21
- from union.io import Dir, File
22
- from union.io.pickle.transformer import FlytePickleTransformer
23
- from union.storage._remote_fs import RemoteFSPathResolver
24
- from union.types import TypeEngine
25
-
26
-
27
- # ---------------------------------------------------
28
- # TODO replace these
29
- class ArtifactQuery:
30
- pass
31
-
32
-
33
- def is_remote(v: str) -> bool:
34
- return False
24
+ from flyte._logging import logger
25
+ from flyte.io import Dir, File
26
+ from flyte.types._pickle import FlytePickleTransformer
35
27
 
36
28
 
37
29
  class StructuredDataset:
@@ -43,26 +35,6 @@ class StructuredDataset:
43
35
  # ---------------------------------------------------
44
36
 
45
37
 
46
- def is_pydantic_basemodel(python_type: typing.Type) -> bool:
47
- """
48
- Checks if the python type is a pydantic BaseModel
49
- """
50
- try:
51
- import pydantic # noqa: F401
52
- except ImportError:
53
- return False
54
- else:
55
- try:
56
- from pydantic import BaseModel as BaseModelV2
57
- from pydantic.v1 import BaseModel as BaseModelV1
58
-
59
- return issubclass(python_type, BaseModelV1) or issubclass(python_type, BaseModelV2)
60
- except ImportError:
61
- from pydantic import BaseModel
62
-
63
- return issubclass(python_type, BaseModel)
64
-
65
-
66
38
  def key_value_callback(_: typing.Any, param: str, values: typing.List[str]) -> typing.Optional[typing.Dict[str, str]]:
67
39
  """
68
40
  Callback for click to parse key-value pairs.
@@ -100,17 +72,13 @@ class DirParamType(click.ParamType):
100
72
  def convert(
101
73
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
102
74
  ) -> typing.Any:
103
- if isinstance(value, ArtifactQuery):
104
- return value
75
+ from flyte.storage import is_remote
105
76
 
106
- # set remote_directory to false if running pyflyte run locally. This makes sure that the original
107
- # directory is used and not a random one.
108
- remote_directory = None if getattr(ctx.obj, "is_remote", False) else False
109
77
  if not is_remote(value):
110
78
  p = pathlib.Path(value)
111
79
  if not p.exists() or not p.is_dir():
112
80
  raise click.BadParameter(f"parameter should be a valid flytedirectory path, {value}")
113
- return Dir(path=value, remote_directory=remote_directory)
81
+ return Dir(path=value)
114
82
 
115
83
 
116
84
  class StructuredDatasetParamType(click.ParamType):
@@ -123,8 +91,6 @@ class StructuredDatasetParamType(click.ParamType):
123
91
  def convert(
124
92
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
125
93
  ) -> typing.Any:
126
- if isinstance(value, ArtifactQuery):
127
- return value
128
94
  if isinstance(value, str):
129
95
  return StructuredDataset(uri=value)
130
96
  elif isinstance(value, StructuredDataset):
@@ -138,22 +104,19 @@ class FileParamType(click.ParamType):
138
104
  def convert(
139
105
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
140
106
  ) -> typing.Any:
141
- if isinstance(value, ArtifactQuery):
142
- return value
143
- # set remote_directory to false if running pyflyte run locally. This makes sure that the original
144
- # file is used and not a random one.
145
- remote_path = None if getattr(ctx.obj, "is_remote", False) else False
107
+ from flyte.storage import is_remote
108
+
146
109
  if not is_remote(value):
147
110
  p = pathlib.Path(value)
148
111
  if not p.exists() or not p.is_file():
149
112
  raise click.BadParameter(f"parameter should be a valid file path, {value}")
150
- return File(path=value, remote_path=remote_path)
113
+ return File.from_existing_remote(value)
151
114
 
152
115
 
153
116
  class PickleParamType(click.ParamType):
154
117
  name = "pickle"
155
118
 
156
- def get_metavar(self, param: click.Parameter) -> t.Optional[str]:
119
+ def get_metavar(self, param: "Parameter", *args) -> t.Optional[str]:
157
120
  return "Python Object <Module>:<Object>"
158
121
 
159
122
  def convert(
@@ -163,7 +126,7 @@ class PickleParamType(click.ParamType):
163
126
  return value
164
127
  parts = value.split(":")
165
128
  if len(parts) != 2:
166
- if ctx and ctx.obj and ctx.obj.verbose > 0:
129
+ if ctx and ctx.obj and ctx.obj.log_level >= 10: # DEBUG level
167
130
  click.echo(f"Did not receive a string in the expected format <MODULE>:<VAR>, falling back to: {value}")
168
131
  return value
169
132
  try:
@@ -185,9 +148,6 @@ class JSONIteratorParamType(click.ParamType):
185
148
  return value
186
149
 
187
150
 
188
- import re
189
-
190
-
191
151
  def parse_iso8601_duration(iso_duration: str) -> datetime.timedelta:
192
152
  pattern = re.compile(
193
153
  r"^P" # Starts with 'P'
@@ -211,10 +171,10 @@ def parse_human_durations(text: str) -> list[datetime.timedelta]:
211
171
  durations = []
212
172
 
213
173
  for part in raw_parts:
214
- part = part.strip().lower()
174
+ new_part = part.strip().lower()
215
175
 
216
176
  # Match 1:24 or :45
217
- m_colon = re.match(r"^(?:(\d+):)?(\d+)$", part)
177
+ m_colon = re.match(r"^(?:(\d+):)?(\d+)$", new_part)
218
178
  if m_colon:
219
179
  minutes = int(m_colon.group(1)) if m_colon.group(1) else 0
220
180
  seconds = int(m_colon.group(2))
@@ -222,7 +182,7 @@ def parse_human_durations(text: str) -> list[datetime.timedelta]:
222
182
  continue
223
183
 
224
184
  # Match "10 days", "1 minute", etc.
225
- m_units = re.match(r"^(\d+)\s*(day|hour|minute|second)s?$", part)
185
+ m_units = re.match(r"^(\d+)\s*(day|hour|minute|second)s?$", new_part)
226
186
  if m_units:
227
187
  value = int(m_units.group(1))
228
188
  unit = m_units.group(2)
@@ -270,9 +230,6 @@ class DateTimeType(click.DateTime):
270
230
  def convert(
271
231
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
272
232
  ) -> typing.Any:
273
- if isinstance(value, ArtifactQuery):
274
- return value
275
-
276
233
  if isinstance(value, str) and " " in value:
277
234
  import re
278
235
 
@@ -303,8 +260,6 @@ class DurationParamType(click.ParamType):
303
260
  def convert(
304
261
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
305
262
  ) -> typing.Any:
306
- if isinstance(value, ArtifactQuery):
307
- return value
308
263
  if value is None:
309
264
  raise click.BadParameter("None value cannot be converted to a Duration type.")
310
265
  return parse_duration(value)
@@ -318,8 +273,6 @@ class EnumParamType(click.Choice):
318
273
  def convert(
319
274
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
320
275
  ) -> enum.Enum:
321
- if isinstance(value, ArtifactQuery):
322
- return value
323
276
  if isinstance(value, self._enum_type):
324
277
  return value
325
278
  return self._enum_type(super().convert(value, param, ctx))
@@ -333,10 +286,7 @@ class UnionParamType(click.ParamType):
333
286
  def __init__(self, types: typing.List[click.ParamType]):
334
287
  super().__init__()
335
288
  self._types = self._sort_precedence(types)
336
-
337
- @property
338
- def name(self) -> str:
339
- return "|".join([t.name for t in self._types])
289
+ self.name = "|".join([t.name for t in self._types])
340
290
 
341
291
  @staticmethod
342
292
  def _sort_precedence(tp: typing.List[click.ParamType]) -> typing.List[click.ParamType]:
@@ -350,7 +300,7 @@ class UnionParamType(click.ParamType):
350
300
  str_types.append(p)
351
301
  else:
352
302
  others.append(p)
353
- return others + str_types + unprocessed
303
+ return others + str_types + unprocessed # type: ignore
354
304
 
355
305
  def convert(
356
306
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
@@ -359,8 +309,6 @@ class UnionParamType(click.ParamType):
359
309
  Important to implement NoneType / Optional.
360
310
  Also could we just determine the click types from the python types
361
311
  """
362
- if isinstance(value, ArtifactQuery):
363
- return value
364
312
  for p in self._types:
365
313
  try:
366
314
  return p.convert(value, param, ctx)
@@ -386,7 +334,7 @@ class JsonParamType(click.ParamType):
386
334
  # We failed to load the json, so we'll try to load it as a file
387
335
  if os.path.exists(value):
388
336
  # if the value is a yaml file, we'll try to load it as yaml
389
- if value.endswith(".yaml") or value.endswith(".yml"):
337
+ if value.endswith((".yaml", "yml")):
390
338
  with open(value, "r") as f:
391
339
  return yaml.safe_load(f)
392
340
  with open(value, "r") as f:
@@ -398,8 +346,6 @@ class JsonParamType(click.ParamType):
398
346
  def convert(
399
347
  self, value: typing.Any, param: typing.Optional[click.Parameter], ctx: typing.Optional[click.Context]
400
348
  ) -> typing.Any:
401
- if isinstance(value, ArtifactQuery):
402
- return value
403
349
  if value is None:
404
350
  raise click.BadParameter("None value cannot be converted to a Json type.")
405
351
 
@@ -407,68 +353,38 @@ class JsonParamType(click.ParamType):
407
353
 
408
354
  # We compare the origin type because the json parsed value for list or dict is always a list or dict without
409
355
  # the covariant type information.
410
- if type(parsed_value) == typing.get_origin(self._python_type) or type(parsed_value) == self._python_type:
356
+ if type(parsed_value) is typing.get_origin(self._python_type) or type(parsed_value) is self._python_type:
411
357
  # Indexing the return value of get_args will raise an error for native dict and list types.
412
358
  # We don't support native list/dict types with nested dataclasses.
413
359
  if get_args(self._python_type) == ():
414
360
  return parsed_value
415
361
  elif isinstance(parsed_value, list) and dataclasses.is_dataclass(get_args(self._python_type)[0]):
416
362
  j = JsonParamType(get_args(self._python_type)[0])
417
- return [j.convert(v, param, ctx) for v in parsed_value]
363
+ # turn object back into json string
364
+ return [j.convert(json.dumps(v), param, ctx) for v in parsed_value]
418
365
  elif isinstance(parsed_value, dict) and dataclasses.is_dataclass(get_args(self._python_type)[1]):
419
366
  j = JsonParamType(get_args(self._python_type)[1])
420
- return {k: j.convert(v, param, ctx) for k, v in parsed_value.items()}
367
+ # turn object back into json string
368
+ return {k: j.convert(json.dumps(v), param, ctx) for k, v in parsed_value.items()}
421
369
 
422
370
  return parsed_value
423
371
 
424
- if is_pydantic_basemodel(self._python_type):
425
- """
426
- This function supports backward compatibility for the Pydantic v1 plugin.
427
- If the class is a Pydantic BaseModel, it attempts to parse JSON input using
428
- the appropriate version of Pydantic (v1 or v2).
429
- """
430
- try:
431
- if importlib.util.find_spec("pydantic.v1") is not None:
432
- from pydantic import BaseModel as BaseModelV2
433
-
434
- if issubclass(self._python_type, BaseModelV2):
435
- return self._python_type.model_validate_json(
436
- json.dumps(parsed_value), strict=False, context={"deserialize": True}
437
- )
438
- except ImportError:
439
- pass
440
-
441
- # The behavior of the Pydantic v1 plugin.
442
- return self._python_type.parse_raw(json.dumps(parsed_value))
443
- return None
372
+ from pydantic import BaseModel
444
373
 
445
-
446
- def modify_literal_uris(lit: Literal):
447
- """
448
- Modifies the literal object recursively to replace the URIs with the native paths.
449
- """
450
- if lit.collection:
451
- for l in lit.collection.literals:
452
- modify_literal_uris(l)
453
- elif lit.map:
454
- for k, v in lit.map.literals.items():
455
- modify_literal_uris(v)
456
- elif lit.scalar:
457
- if lit.scalar.blob and lit.scalar.blob.uri and lit.scalar.blob.uri.startswith(RemoteFSPathResolver.protocol):
458
- lit.scalar.blob._uri = RemoteFSPathResolver.resolve_remote_path(lit.scalar.blob.uri)
459
- elif lit.scalar.union:
460
- modify_literal_uris(lit.scalar.union.value)
461
- elif (
462
- lit.scalar.structured_dataset
463
- and lit.scalar.structured_dataset.uri
464
- and lit.scalar.structured_dataset.uri.startswith(RemoteFSPathResolver.protocol)
465
- ):
466
- lit.scalar.structured_dataset._uri = RemoteFSPathResolver.resolve_remote_path(
467
- lit.scalar.structured_dataset.uri
374
+ if issubclass(self._python_type, BaseModel):
375
+ return typing.cast(BaseModel, self._python_type).model_validate_json(
376
+ json.dumps(parsed_value), strict=False, context={"deserialize": True}
468
377
  )
378
+ elif dataclasses.is_dataclass(self._python_type):
379
+ from mashumaro.codecs.json import JSONDecoder
469
380
 
381
+ decoder = JSONDecoder(self._python_type)
382
+ return decoder.decode(value)
470
383
 
471
- SIMPLE_TYPE_CONVERTER: typing.Dict[SimpleType, click.ParamType] = {
384
+ return parsed_value
385
+
386
+
387
+ SIMPLE_TYPE_CONVERTER = {
472
388
  SimpleType.FLOAT: click.FLOAT,
473
389
  SimpleType.INTEGER: click.INT,
474
390
  SimpleType.STRING: click.STRING,
@@ -482,7 +398,7 @@ def literal_type_to_click_type(lt: LiteralType, python_type: typing.Type) -> cli
482
398
  """
483
399
  Converts a Flyte LiteralType given a python_type to a click.ParamType
484
400
  """
485
- if lt.simple:
401
+ if lt.HasField("simple"):
486
402
  if lt.simple == SimpleType.STRUCT:
487
403
  ct = JsonParamType(python_type)
488
404
  ct.name = f"JSON object {python_type.__name__}"
@@ -491,38 +407,38 @@ def literal_type_to_click_type(lt: LiteralType, python_type: typing.Type) -> cli
491
407
  return SIMPLE_TYPE_CONVERTER[lt.simple]
492
408
  raise NotImplementedError(f"Type {lt.simple} is not supported in pyflyte run")
493
409
 
494
- if lt.enum_type:
495
- return EnumParamType(python_type) # type: ignore
496
-
497
- if lt.structured_dataset_type:
410
+ if lt.HasField("structured_dataset_type"):
498
411
  return StructuredDatasetParamType()
499
412
 
500
- if lt.collection_type or lt.map_value_type:
413
+ if lt.HasField("collection_type") or lt.HasField("map_value_type"):
501
414
  ct = JsonParamType(python_type)
502
- if lt.collection_type:
415
+ if lt.HasField("collection_type"):
503
416
  ct.name = "json list"
504
417
  else:
505
418
  ct.name = "json dictionary"
506
419
  return ct
507
420
 
508
- if lt.blob:
421
+ if lt.HasField("blob"):
509
422
  if lt.blob.dimensionality == BlobType.BlobDimensionality.SINGLE:
510
423
  if lt.blob.format == FlytePickleTransformer.PYTHON_PICKLE_FORMAT:
511
424
  return PickleParamType()
425
+ # TODO: Add JSONIteratorTransformer
512
426
  # elif lt.blob.format == JSONIteratorTransformer.JSON_ITERATOR_FORMAT:
513
427
  # return JSONIteratorParamType()
514
428
  return FileParamType()
515
429
  return DirParamType()
516
430
 
517
- if lt.union_type:
431
+ if lt.HasField("union_type"):
518
432
  cts = []
519
433
  for i in range(len(lt.union_type.variants)):
520
434
  variant = lt.union_type.variants[i]
521
435
  variant_python_type = typing.get_args(python_type)[i]
522
- ct = literal_type_to_click_type(variant, variant_python_type)
523
- cts.append(ct)
436
+ cts.append(literal_type_to_click_type(variant, variant_python_type))
524
437
  return UnionParamType(cts)
525
438
 
439
+ if lt.HasField("enum_type"):
440
+ return EnumParamType(python_type) # type: ignore
441
+
526
442
  return click.UNPROCESSED
527
443
 
528
444
 
@@ -533,9 +449,7 @@ class FlyteLiteralConverter(object):
533
449
  self,
534
450
  literal_type: LiteralType,
535
451
  python_type: typing.Type,
536
- is_remote: bool,
537
452
  ):
538
- self._is_remote = is_remote
539
453
  self._literal_type = literal_type
540
454
  self._python_type = python_type
541
455
  self._click_type = literal_type_to_click_type(literal_type, python_type)
@@ -551,25 +465,15 @@ class FlyteLiteralConverter(object):
551
465
  self, ctx: click.Context, param: typing.Optional[click.Parameter], value: typing.Any
552
466
  ) -> typing.Union[Literal, typing.Any]:
553
467
  """
554
- Convert the value to a Flyte Literal or a python native type. This is used by click to convert the input.
468
+ Convert the value to a python native type. This is used by click to convert the input.
555
469
  """
556
- if isinstance(value, ArtifactQuery):
557
- return value
558
470
  try:
559
471
  # If the expected Python type is datetime.date, adjust the value to date
560
472
  if self._python_type is datetime.date:
561
473
  # Click produces datetime, so converting to date to avoid type mismatch error
562
474
  value = value.date()
563
- # If the input matches the default value in the launch plan, serialization can be skipped.
564
- if param and value == param.default:
565
- return None
566
475
 
567
- # If this is used for remote execution, then we need to convert it back to a python native type
568
- if not self._is_remote:
569
- return value
570
-
571
- lit = asyncio.run(TypeEngine.to_literal(value, self._python_type, self._literal_type))
572
- return lit
476
+ return value
573
477
  except click.BadParameter:
574
478
  raise
575
479
  except Exception as e:
@@ -577,3 +481,58 @@ class FlyteLiteralConverter(object):
577
481
  f"Failed to convert param: {param if param else 'NA'}, value: {value} to type: {self._python_type}."
578
482
  f" Reason {e}"
579
483
  ) from e
484
+
485
+
486
+ def to_click_option(
487
+ input_name: str,
488
+ literal_var: Variable,
489
+ python_type: typing.Type,
490
+ default_val: typing.Any,
491
+ ) -> click.Option:
492
+ """
493
+ This handles converting workflow input types to supported click parameters with callbacks to initialize
494
+ the input values to their expected types.
495
+ """
496
+ from flyteidl.core.types_pb2 import SimpleType
497
+
498
+ if input_name != input_name.lower():
499
+ # Click does not support uppercase option names: https://github.com/pallets/click/issues/837
500
+ raise ValueError(f"Workflow input name must be lowercase: {input_name!r}")
501
+
502
+ literal_converter = FlyteLiteralConverter(
503
+ literal_type=literal_var.type,
504
+ python_type=python_type,
505
+ )
506
+
507
+ if literal_converter.is_bool() and not default_val:
508
+ default_val = False
509
+
510
+ description_extra = ""
511
+ if literal_var.type.simple == SimpleType.STRUCT:
512
+ if default_val:
513
+ # pydantic v2
514
+ if hasattr(default_val, "model_dump_json"):
515
+ default_val = default_val.model_dump_json()
516
+ else:
517
+ encoder = JSONEncoder(python_type)
518
+ default_val = encoder.encode(default_val)
519
+ if literal_var.type.metadata:
520
+ description_extra = f": {MessageToDict(literal_var.type.metadata)}"
521
+
522
+ # If a query has been specified, the input is never strictly required at this layer
523
+ required = False if default_val is not None else True
524
+ is_flag: typing.Optional[bool] = None
525
+ if literal_converter.is_bool():
526
+ required = False
527
+ is_flag = True
528
+
529
+ return click.Option(
530
+ param_decls=[f"--{input_name}"],
531
+ type=literal_converter.click_type,
532
+ is_flag=is_flag,
533
+ default=default_val,
534
+ show_default=True,
535
+ required=required,
536
+ help=literal_var.description + description_extra,
537
+ callback=literal_converter.convert,
538
+ )
@@ -1,22 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
4
+ import inspect
3
5
  from dataclasses import dataclass, field, fields
4
6
  from pathlib import Path
5
7
  from types import ModuleType
6
8
  from typing import Any, Dict, List, cast
7
9
 
8
10
  import click
9
- from click import Context
11
+ from click import Context, Parameter
10
12
  from rich.console import Console
11
13
  from typing_extensions import get_args
12
14
 
13
- import flyte
14
-
15
15
  from .._code_bundle._utils import CopyFiles
16
16
  from .._task import TaskTemplate
17
17
  from ..remote import Run
18
18
  from . import _common as common
19
19
  from ._common import CLIConfig
20
+ from ._params import to_click_option
20
21
 
21
22
 
22
23
  @dataclass
@@ -48,6 +49,28 @@ class RunArguments:
48
49
  )
49
50
  },
50
51
  )
52
+ name: str | None = field(
53
+ default=None,
54
+ metadata={
55
+ "click.option": click.Option(
56
+ ["--name"],
57
+ type=str,
58
+ help="Name of the run. If not provided, a random name will be generated.",
59
+ )
60
+ },
61
+ )
62
+ follow: bool = field(
63
+ default=True,
64
+ metadata={
65
+ "click.option": click.Option(
66
+ ["--follow", "-f"],
67
+ is_flag=True,
68
+ default=False,
69
+ help="Wait and watch logs for the parent action. If not provided, the CLI will exit after "
70
+ "successfully launching a remote execution with a link to the UI.",
71
+ )
72
+ },
73
+ )
51
74
 
52
75
  @classmethod
53
76
  def from_dict(cls, d: Dict[str, Any]) -> RunArguments:
@@ -70,24 +93,60 @@ class RunTaskCommand(click.Command):
70
93
  super().__init__(obj_name, *args, **kwargs)
71
94
 
72
95
  def invoke(self, ctx: Context):
73
- obj: CLIConfig = ctx.obj or CLIConfig()
96
+ obj: CLIConfig = ctx.obj
97
+ if obj is None:
98
+ import flyte.config
99
+
100
+ obj = CLIConfig(flyte.config.auto(), ctx)
101
+
74
102
  obj.init(self.run_args.project, self.run_args.domain)
75
103
 
76
- r = flyte.with_runcontext(
77
- copy_style=self.run_args.copy_style,
78
- version=self.run_args.copy_style,
79
- mode="local" if self.run_args.local else "remote",
80
- ).run(self.obj)
81
- if isinstance(r, Run) and r.action is not None:
82
- console = Console()
83
- console.print(
84
- common.get_panel(
85
- "Run",
86
- f"[green bold]Created Run: {r.name} [/green bold] "
87
- f"(Project: {r.action.action_id.run.project}, Domain: {r.action.action_id.run.domain})\n\n"
88
- f"[blue bold]{r.url}[/blue bold]",
104
+ async def _run():
105
+ import flyte
106
+
107
+ r = flyte.with_runcontext(
108
+ copy_style=self.run_args.copy_style,
109
+ mode="local" if self.run_args.local else "remote",
110
+ name=self.run_args.name,
111
+ ).run(self.obj, **ctx.params)
112
+ if isinstance(r, Run) and r.action is not None:
113
+ console = Console()
114
+ console.print(
115
+ common.get_panel(
116
+ "Run",
117
+ f"[green bold]Created Run: {r.name} [/green bold] "
118
+ f"(Project: {r.action.action_id.run.project}, Domain: {r.action.action_id.run.domain})\n"
119
+ f"➡️ [blue bold]{r.url}[/blue bold]",
120
+ )
89
121
  )
90
- )
122
+ if self.run_args.follow:
123
+ console.print(
124
+ "[dim]Log streaming enabled, will wait for task to start running "
125
+ "and log stream to be available[/dim]"
126
+ )
127
+ await r.show_logs(max_lines=30, show_ts=True, raw=False)
128
+
129
+ asyncio.run(_run())
130
+
131
+ def get_params(self, ctx: Context) -> List[Parameter]:
132
+ # Note this function may be called multiple times by click.
133
+ task = self.obj
134
+ from .._internal.runtime.types_serde import transform_native_to_typed_interface
135
+
136
+ interface = transform_native_to_typed_interface(task.native_interface)
137
+ if interface is None:
138
+ return super().get_params(ctx)
139
+ inputs_interface = task.native_interface.inputs
140
+
141
+ params: List[Parameter] = []
142
+ for name, var in interface.inputs.variables.items():
143
+ default_val = None
144
+ if inputs_interface[name][1] is not inspect._empty:
145
+ default_val = inputs_interface[name][1]
146
+ params.append(to_click_option(name, var, inputs_interface[name][0], default_val))
147
+
148
+ self.params = params
149
+ return super().get_params(ctx)
91
150
 
92
151
 
93
152
  class TaskPerFileGroup(common.ObjectsPerFileGroup):
@@ -142,11 +201,31 @@ class TaskFiles(common.FileGroup):
142
201
  filename=Path(filename),
143
202
  run_args=run_args,
144
203
  name=filename,
145
- help=f"Run, functions decorated `env.task` or instances of Tasks in {filename}",
204
+ help=f"Run, functions decorated with `env.task` in {filename}",
146
205
  )
147
206
 
148
207
 
149
208
  run = TaskFiles(
150
209
  name="run",
151
- help="Run a task from a python file",
210
+ help="""
211
+ Run a task from a python file.
212
+
213
+ Example usage:
214
+ ```bash
215
+ flyte run --name examples/basics/hello.py my_task --arg1 value1 --arg2 value2
216
+ ```
217
+ Note: all arguments for the run command are provided right after the `run` command and before the file name.
218
+
219
+ You can also specify the project and domain using the `--project` and `--domain` options, respectively. These
220
+ options can be set in the config file or passed as command line arguments.
221
+
222
+ Note: The arguments for the task are provided after the task name and can be retrieved using `--help`
223
+ Example:
224
+ ```bash
225
+ flyte run --name examples/basics/hello.py my_task --help
226
+ ```
227
+
228
+ To run a task locally, use the `--local` flag. This will run the task in the local environment instead of the remote
229
+ Flyte environment.
230
+ """,
152
231
  )