Skip to content

Commit 6ebcb96

Browse files
committed
Merge branch 'master' of github.com:flyteorg/flytekit into Add_user_specified_field
2 parents b5782d4 + eb5a67f commit 6ebcb96

34 files changed

Lines changed: 658 additions & 119 deletions

File tree

flytekit/clis/sdk_in_container/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class RunLevelParams(PyFlyteParams):
160160
)
161161
poll_interval: int = make_click_option_field(
162162
click.Option(
163-
param_decls=["-i", "--poll-interval", "poll_interval"],
163+
param_decls=["--poll-interval", "poll_interval"],
164164
required=False,
165165
type=int,
166166
default=None,

flytekit/core/base_task.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ class TaskMetadata(object):
131131
pod_template_name (Optional[str]): The name of an existing PodTemplate resource in the cluster which will be used for this task.
132132
generates_deck (bool): Indicates whether the task will generate a Deck URI.
133133
is_eager (bool): Indicates whether the task should be treated as eager.
134+
labels (Optional[dict[str, str]]): Labels to be applied to the task resource.
135+
annotations (Optional[dict[str, str]]): Annotations to be applied to the task resource.
134136
"""
135137

136138
cache: bool = False
@@ -144,6 +146,8 @@ class TaskMetadata(object):
144146
pod_template_name: Optional[str] = None
145147
generates_deck: bool = False
146148
is_eager: bool = False
149+
labels: Optional[dict[str, str]] = None
150+
annotations: Optional[dict[str, str]] = None
147151

148152
def __post_init__(self):
149153
if self.timeout:
@@ -185,6 +189,10 @@ def to_taskmetadata_model(self) -> _task_model.TaskMetadata:
185189
pod_template_name=self.pod_template_name,
186190
cache_ignore_input_vars=self.cache_ignore_input_vars,
187191
is_eager=self.is_eager,
192+
k8s_object_metadata=_task_model.K8sObjectMetadata(
193+
labels=self.labels,
194+
annotations=self.annotations,
195+
),
188196
)
189197

190198

flytekit/core/python_auto_container.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ def __init__(
100100
kwargs["metadata"] = kwargs["metadata"] if "metadata" in kwargs else TaskMetadata()
101101
kwargs["metadata"].pod_template_name = pod_template_name
102102

103+
if kwargs.get("labels") is not None:
104+
kwargs["metadata"].labels = kwargs["labels"]
105+
if kwargs.get("annotations") is not None:
106+
kwargs["metadata"].annotations = kwargs["annotations"]
107+
103108
self._container_image = container_image
104109
# TODO(katrogan): Implement resource overrides
105110

flytekit/core/task.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def task(
128128
pickle_untyped: bool = ...,
129129
shared_memory: Optional[Union[L[True], str]] = None,
130130
resources: Optional[Resources] = ...,
131+
labels: Optional[dict[str, str]] = ...,
132+
annotations: Optional[dict[str, str]] = ...,
131133
**kwargs,
132134
) -> Callable[[Callable[..., FuncOut]], PythonFunctionTask[T]]: ...
133135

@@ -167,6 +169,8 @@ def task(
167169
pickle_untyped: bool = ...,
168170
shared_memory: Optional[Union[L[True], str]] = ...,
169171
resources: Optional[Resources] = ...,
172+
labels: Optional[dict[str, str]] = ...,
173+
annotations: Optional[dict[str, str]] = ...,
170174
**kwargs,
171175
) -> Union[Callable[P, FuncOut], PythonFunctionTask[T]]: ...
172176

@@ -211,6 +215,8 @@ def task(
211215
pickle_untyped: bool = False,
212216
shared_memory: Optional[Union[L[True], str]] = None,
213217
resources: Optional[Resources] = None,
218+
labels: Optional[dict[str, str]] = None,
219+
annotations: Optional[dict[str, str]] = None,
214220
**kwargs,
215221
) -> Union[
216222
Callable[P, FuncOut],
@@ -348,6 +354,8 @@ def launch_dynamically():
348354
first value is the request and the second value is the limit. If the value is a single value, then both the
349355
requests and limit is set to that value. For example, the `Resource(cpu=("1", "2"), mem="1Gi")` will set the cpu
350356
request to 1, cpu limit to 2, and mem request to 1Gi.
357+
:param labels: Labels to be applied to the task resource.
358+
:param annotations: Annotations to be applied to the task resource.
351359
"""
352360
# Maintain backwards compatibility with the old cache parameters, while cleaning up the task function definition.
353361
cache_serialize = kwargs.pop("cache_serialize", None)
@@ -445,6 +453,8 @@ def wrapper(fn: Callable[P, FuncOut]) -> PythonFunctionTask[T]:
445453
pickle_untyped=pickle_untyped,
446454
shared_memory=shared_memory,
447455
resources=resources,
456+
labels=labels,
457+
annotations=annotations,
448458
)
449459
update_wrapper(task_instance, decorated_fn)
450460
return task_instance

flytekit/core/type_engine.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -660,10 +660,8 @@ def get_literal_type(self, t: Type[T]) -> LiteralType:
660660
python_type = hints.get(name, field.type)
661661
literal_type[name] = TypeEngine.to_literal_type(python_type)
662662
except Exception as e:
663-
logger.warning(
664-
"Field {} of type {} cannot be converted to a literal type. Error: {}".format(
665-
field.name, field.type, e
666-
)
663+
logger.debug(
664+
f"Field {field.name} of type {field.type} cannot be converted to a literal type. Error: {e}"
667665
)
668666

669667
# This is for attribute access in FlytePropeller.
@@ -1771,6 +1769,19 @@ def _type_essence(x: LiteralType) -> LiteralType:
17711769

17721770

17731771
def _are_types_castable(upstream: LiteralType, downstream: LiteralType) -> bool:
1772+
if upstream.union_type is not None:
1773+
# for each upstream variant, there must be a compatible type downstream
1774+
for v in upstream.union_type.variants:
1775+
if not _are_types_castable(v, downstream):
1776+
return False
1777+
return True
1778+
1779+
if downstream.union_type is not None:
1780+
# there must be a compatible downstream type
1781+
for v in downstream.union_type.variants:
1782+
if _are_types_castable(upstream, v):
1783+
return True
1784+
17741785
if upstream.collection_type is not None:
17751786
if downstream.collection_type is None:
17761787
return False
@@ -1816,19 +1827,6 @@ def _are_types_castable(upstream: LiteralType, downstream: LiteralType) -> bool:
18161827

18171828
return True
18181829

1819-
if upstream.union_type is not None:
1820-
# for each upstream variant, there must be a compatible type downstream
1821-
for v in upstream.union_type.variants:
1822-
if not _are_types_castable(v, downstream):
1823-
return False
1824-
return True
1825-
1826-
if downstream.union_type is not None:
1827-
# there must be a compatible downstream type
1828-
for v in downstream.union_type.variants:
1829-
if _are_types_castable(upstream, v):
1830-
return True
1831-
18321830
if upstream.enum_type is not None:
18331831
# enums are castable to string
18341832
if downstream.simple == SimpleType.STRING:
@@ -2115,7 +2113,7 @@ async def dict_to_generic_literal(
21152113
),
21162114
metadata={"format": "pickle"},
21172115
)
2118-
raise TypeTransformerFailedError(f"Cannot convert `{v}` to Flyte Literal.\n" f"Error Message: {e}")
2116+
raise TypeTransformerFailedError(f"Cannot convert `{v}` to Flyte Literal.\nError Message: {e}")
21192117

21202118
@staticmethod
21212119
async def dict_to_binary_literal(
@@ -2141,7 +2139,7 @@ async def dict_to_binary_literal(
21412139
),
21422140
metadata={"format": "pickle"},
21432141
)
2144-
raise TypeTransformerFailedError(f"Cannot convert `{v}` to Flyte Literal.\n" f"Error Message: {e}")
2142+
raise TypeTransformerFailedError(f"Cannot convert `{v}` to Flyte Literal.\nError Message: {e}")
21452143

21462144
@staticmethod
21472145
def is_pickle(python_type: Type[dict]) -> bool:

flytekit/extras/accelerators.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ def to_flyte_idl(self) -> tasks_pb2.GPUAccelerator:
106106
#: `NVIDIA L4 Tensor Core GPU https://www.nvidia.com/en-us/data-center/l4
107107
L4_VWS = GPUAccelerator("nvidia-l4-vws")
108108

109+
#: use this constant to specify that the task should run on an
110+
#: `NVIDIA L40S Tensor Core GPU https://www.nvidia.com/en-us/data-center/l40s
111+
L40S = GPUAccelerator("nvidia-l40s")
112+
109113
#: use this constant to specify that the task should run on an
110114
#: `NVIDIA Tesla K80 GPU https://www.nvidia.com/en-gb/data-center/tesla-k80
111115
K80 = GPUAccelerator("nvidia-tesla-k80")
@@ -130,6 +134,14 @@ def to_flyte_idl(self) -> tasks_pb2.GPUAccelerator:
130134
#: `NVIDIA Tesla V100 GPU https://images.nvidia.com/content/technologies/volta/pdf/tesla-volta-v100-datasheet-letter-fnl-web.pdf
131135
V100 = GPUAccelerator("nvidia-tesla-v100")
132136

137+
#: use this constant to specify that the task should run on an
138+
#: `NVIDIA H100 GPU https://www.nvidia.com/en-us/data-center/h100
139+
H100 = GPUAccelerator("nvidia-h100")
140+
141+
#: use this constant to specify that the task should run on an
142+
#: `NVIDIA H200 GPU https://www.nvidia.com/en-us/data-center/h200
143+
H200 = GPUAccelerator("nvidia-h200")
144+
133145

134146
class MultiInstanceGPUAccelerator(BaseAccelerator):
135147
"""

flytekit/image_spec/default_builder.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
--mount=type=bind,target=uv.lock,src=uv.lock \
3030
--mount=type=bind,target=pyproject.toml,src=pyproject.toml \
3131
$PIP_SECRET_MOUNT \
32-
uv sync $PIP_INSTALL_ARGS
32+
uv sync $PIP_INSTALL_ARGS && \
33+
chown -R flytekit /root/.venv
3334
WORKDIR /
3435
3536
# Update PATH and UV_PYTHON to point to the venv created by uv sync
@@ -54,12 +55,12 @@
5455
--mount=type=bind,target=poetry.lock,src=poetry.lock \
5556
--mount=type=bind,target=pyproject.toml,src=pyproject.toml \
5657
$PIP_SECRET_MOUNT \
57-
poetry install $PIP_INSTALL_ARGS
58-
58+
poetry install $PIP_INSTALL_ARGS && \
59+
chown -R flytekit /root/.venv
5960
WORKDIR /
6061
6162
# Update PATH and UV_PYTHON to point to venv
62-
ENV PATH="/root/.venv/bin:$$PATH" \
63+
ENV PATH="/root/.venv/bin:$$PATH" \
6364
UV_PYTHON=/root/.venv/bin/python
6465
"""
6566
)
@@ -81,14 +82,19 @@
8182
$APT_PACKAGES
8283
""")
8384

85+
# make sure that micromamba python installation is owned by flytekit user
8486
MICROMAMBA_INSTALL_COMMAND_TEMPLATE = Template("""\
8587
RUN --mount=type=cache,sharing=locked,mode=0777,target=/opt/micromamba/pkgs,\
8688
id=micromamba \
8789
--mount=from=micromamba,source=/usr/bin/micromamba,target=/usr/bin/micromamba \
8890
micromamba config set use_lockfiles False && \
89-
micromamba create -n runtime --root-prefix /opt/micromamba \
91+
( micromamba create -n runtime --root-prefix /opt/micromamba \
92+
-c conda-forge $CONDA_CHANNELS \
93+
python=$PYTHON_VERSION $CONDA_PACKAGES \
94+
|| micromamba install -n runtime --root-prefix /opt/micromamba \
9095
-c conda-forge $CONDA_CHANNELS \
91-
python=$PYTHON_VERSION $CONDA_PACKAGES
96+
python=$PYTHON_VERSION $CONDA_PACKAGES ) && \
97+
chown -R flytekit /opt/micromamba
9298
""")
9399

94100
DOCKER_FILE_TEMPLATE = Template("""\
@@ -98,6 +104,7 @@
98104
99105
FROM $BASE_IMAGE
100106
107+
WORKDIR /
101108
USER root
102109
$APT_INSTALL_COMMAND
103110
RUN --mount=from=micromamba,source=/etc/ssl/certs/ca-certificates.crt,target=/tmp/ca-certificates.crt \
@@ -118,7 +125,7 @@
118125
SSL_CERT_DIR=/etc/ssl/certs \
119126
$ENV
120127
121-
$UV_PYTHON_INSTALL_COMMAND
128+
$PYTHON_INSTALL_COMMAND
122129
123130
# Adds nvidia just in case it exists
124131
ENV PATH="$$PATH:/usr/local/nvidia/bin:/usr/local/cuda/bin" \
@@ -336,7 +343,7 @@ def create_docker_context(image_spec: ImageSpec, tmp_dir: Path):
336343
)
337344
raise ValueError(msg)
338345

339-
uv_python_install_command = prepare_python_install(image_spec, tmp_dir)
346+
python_install_command = prepare_python_install(image_spec, tmp_dir)
340347
env_dict = {"PYTHONPATH": "/root"}
341348

342349
if image_spec.env:
@@ -422,11 +429,11 @@ def create_docker_context(image_spec: ImageSpec, tmp_dir: Path):
422429
_f_img_id_env = f"{_F_IMG_ID}={image_spec.id}"
423430

424431
docker_content = DOCKER_FILE_TEMPLATE.substitute(
425-
UV_PYTHON_INSTALL_COMMAND=uv_python_install_command,
426-
APT_INSTALL_COMMAND=apt_install_command,
427432
INSTALL_PYTHON_TEMPLATE=python_install_template.template,
428433
EXTRA_PATH=python_install_template.extra_path,
429434
PYTHON_EXEC=python_install_template.python_exec,
435+
APT_INSTALL_COMMAND=apt_install_command,
436+
PYTHON_INSTALL_COMMAND=python_install_command,
430437
BASE_IMAGE=base_image,
431438
ENV=env,
432439
_F_IMG_ID_ENV=_f_img_id_env,

flytekit/models/core/workflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ def to_flyte_idl(self) -> _core_workflow.ArrayNode:
423423
execution_mode=self._execution_mode,
424424
is_original_sub_node_interface=BoolValue(value=self._is_original_sub_node_interface),
425425
data_mode=self._data_mode,
426-
bound_inputs=self._bound_inputs,
426+
bound_inputs=sorted(self._bound_inputs),
427427
)
428428

429429
@classmethod

flytekit/models/task.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def __init__(
185185
cache_ignore_input_vars,
186186
is_eager: bool = False,
187187
generates_deck: bool = False,
188+
k8s_object_metadata: typing.Optional["K8sObjectMetadata"] = None,
188189
):
189190
"""
190191
Information needed at runtime to determine behavior such as whether or not outputs are discoverable, timeouts,
@@ -208,6 +209,7 @@ def __init__(
208209
:param pod_template_name: The name of the existing PodTemplate resource which will be used in this task.
209210
:param cache_ignore_input_vars: Input variables that should not be included when calculating hash for cache.
210211
:param is_eager:
212+
:param metadata: Kubernetes metadata for the task.
211213
"""
212214
self._discoverable = discoverable
213215
self._runtime = runtime
@@ -221,6 +223,7 @@ def __init__(
221223
self._cache_ignore_input_vars = cache_ignore_input_vars
222224
self._is_eager = is_eager
223225
self._generates_deck = generates_deck
226+
self._k8s_object_metadata = k8s_object_metadata
224227

225228
@property
226229
def is_eager(self):
@@ -318,6 +321,14 @@ def cache_ignore_input_vars(self):
318321
"""
319322
return self._cache_ignore_input_vars
320323

324+
@property
325+
def k8s_object_metadata(self) -> typing.Optional["K8sObjectMetadata"]:
326+
"""
327+
Kubernetes metadata for the task.
328+
:rtype: K8sObjectMetadata
329+
"""
330+
return self._k8s_object_metadata
331+
321332
def to_flyte_idl(self):
322333
"""
323334
:rtype: flyteidl.admin.task_pb2.TaskMetadata
@@ -334,6 +345,7 @@ def to_flyte_idl(self):
334345
cache_ignore_input_vars=self.cache_ignore_input_vars,
335346
is_eager=self.is_eager,
336347
generates_deck=BoolValue(value=self.generates_deck),
348+
metadata=self.k8s_object_metadata.to_flyte_idl() if self.k8s_object_metadata else None,
337349
)
338350
if self.timeout:
339351
tm.timeout.FromTimedelta(self.timeout)
@@ -358,6 +370,9 @@ def from_flyte_idl(cls, pb2_object: _core_task.TaskMetadata):
358370
cache_ignore_input_vars=pb2_object.cache_ignore_input_vars,
359371
is_eager=pb2_object.is_eager,
360372
generates_deck=pb2_object.generates_deck.value if pb2_object.HasField("generates_deck") else False,
373+
k8s_object_metadata=K8sObjectMetadata.from_flyte_idl(pb2_object.metadata)
374+
if pb2_object.HasField("metadata")
375+
else None,
361376
)
362377

363378

@@ -985,7 +1000,11 @@ def from_flyte_idl(cls, pb2_object):
9851000

9861001

9871002
class K8sObjectMetadata(_common.FlyteIdlEntity):
988-
def __init__(self, labels: typing.Dict[str, str] = None, annotations: typing.Dict[str, str] = None):
1003+
def __init__(
1004+
self,
1005+
labels: typing.Optional[typing.Dict[str, str]] = None,
1006+
annotations: typing.Optional[typing.Dict[str, str]] = None,
1007+
):
9891008
"""
9901009
This defines additional metadata for building a kubernetes pod.
9911010
"""

0 commit comments

Comments
 (0)