flyte 0.2.0b25__py3-none-any.whl → 0.2.0b27__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.

flyte/_bin/runtime.py CHANGED
@@ -82,6 +82,9 @@ def main(
82
82
  ):
83
83
  sys.path.insert(0, ".")
84
84
 
85
+ import faulthandler
86
+ import signal
87
+
85
88
  import flyte
86
89
  import flyte._utils as utils
87
90
  from flyte._initialize import init
@@ -91,8 +94,10 @@ def main(
91
94
  from flyte._logging import logger
92
95
  from flyte.models import ActionID, Checkpoints, CodeBundle, RawDataPath
93
96
 
94
- logger.info(f"Initializing flyte runtime - version {flyte.__version__}")
97
+ logger.info("Registering faulthandler for SIGUSR1")
98
+ faulthandler.register(signal.SIGUSR1)
95
99
 
100
+ logger.info(f"Initializing flyte runtime - version {flyte.__version__}")
96
101
  assert org, "Org is required for now"
97
102
  assert project, "Project is required"
98
103
  assert domain, "Domain is required"
flyte/_image.py CHANGED
@@ -355,7 +355,11 @@ class Image:
355
355
 
356
356
  @classmethod
357
357
  def _get_default_image_for(
358
- cls, python_version: Tuple[int, int], flyte_version: Optional[str] = None, install_flyte: bool = True
358
+ cls,
359
+ python_version: Tuple[int, int],
360
+ flyte_version: Optional[str] = None,
361
+ install_flyte: bool = True,
362
+ platform: Optional[Tuple[Architecture, ...]] = None,
359
363
  ) -> Image:
360
364
  # Would love a way to move this outside of this class (but still needs to be accessible via Image.auto())
361
365
  # this default image definition may need to be updated once there is a released pypi version
@@ -377,7 +381,7 @@ class Image:
377
381
  base_image=f"python:{python_version[0]}.{python_version[1]}-slim-bookworm",
378
382
  registry=_BASE_REGISTRY,
379
383
  name=_DEFAULT_IMAGE_NAME,
380
- platform=("linux/amd64", "linux/arm64"),
384
+ platform=("linux/amd64", "linux/arm64") if platform is None else platform,
381
385
  )
382
386
  labels_and_user = _DockerLines(
383
387
  (
@@ -430,6 +434,7 @@ class Image:
430
434
  install_flyte: bool = True,
431
435
  registry: Optional[str] = None,
432
436
  name: Optional[str] = None,
437
+ platform: Optional[Tuple[Architecture, ...]] = None,
433
438
  ) -> Image:
434
439
  """
435
440
  Use this method to start using the default base image, built from this library's base Dockerfile
@@ -440,6 +445,8 @@ class Image:
440
445
  :param install_flyte: If True, will install the flyte library in the image
441
446
  :param registry: Registry to use for the image
442
447
  :param name: Name of the image if you want to override the default name
448
+ :param platform: Platform to use for the image, default is linux/amd64, use tuple for multiple values
449
+ Example: ("linux/amd64", "linux/arm64")
443
450
 
444
451
  :return: Image
445
452
  """
@@ -447,7 +454,10 @@ class Image:
447
454
  python_version = _detect_python_version()
448
455
 
449
456
  base_image = cls._get_default_image_for(
450
- python_version=python_version, flyte_version=flyte_version, install_flyte=install_flyte
457
+ python_version=python_version,
458
+ flyte_version=flyte_version,
459
+ install_flyte=install_flyte,
460
+ platform=platform,
451
461
  )
452
462
 
453
463
  if registry and name:
@@ -481,7 +491,7 @@ class Image:
481
491
  extra_index_urls: Union[str, List[str], Tuple[str, ...], None] = None,
482
492
  pre: bool = False,
483
493
  extra_args: Optional[str] = None,
484
- arch: Union[Architecture, Tuple[Architecture, ...]] = "linux/amd64",
494
+ platform: Optional[Tuple[Architecture, ...]] = None,
485
495
  ) -> Image:
486
496
  """
487
497
  Use this method to create a new image with the specified uv script.
@@ -506,7 +516,7 @@ class Image:
506
516
  :param python_version: Python version to use for the image, if not specified, will use the current Python
507
517
  version
508
518
  :param script: path to the uv script
509
- :param arch: architecture to use for the image, default is linux/amd64, use tuple for multiple values
519
+ :param platform: architecture to use for the image, default is linux/amd64, use tuple for multiple values
510
520
  :param python_version: Python version for the image, if not specified, will use the current Python version
511
521
  :param index_url: index url to use for pip install, default is None
512
522
  :param extra_index_urls: extra index urls to use for pip install, default is None
@@ -530,7 +540,7 @@ class Image:
530
540
  raise ValueError("registry must be specified")
531
541
 
532
542
  # todo: arch
533
- img = cls.from_debian_base(registry=registry, name=name, python_version=python_version)
543
+ img = cls.from_debian_base(registry=registry, name=name, python_version=python_version, platform=platform)
534
544
 
535
545
  # add ca-certificates to the image by default
536
546
  img = img.with_apt_packages("ca-certificates")
@@ -106,10 +106,12 @@ class LocalController:
106
106
  raise exc
107
107
  else:
108
108
  raise flyte.errors.RuntimeSystemError("BadError", "Unknown error")
109
- if _task.native_interface.outputs and out is not None:
109
+ if _task.native_interface.outputs:
110
+ if out is None:
111
+ raise flyte.errors.RuntimeSystemError("BadOutput", "Task output not captured.")
110
112
  result = await convert.convert_outputs_to_native(_task.native_interface, out)
111
113
  return result
112
- return out
114
+ return None
113
115
 
114
116
  def submit_sync(self, _task: TaskTemplate, *args, **kwargs) -> concurrent.futures.Future:
115
117
  name = threading.current_thread().name + f"PID:{os.getpid()}"
@@ -120,13 +120,19 @@ async def convert_from_native_to_inputs(interface: NativeInterface, *args, **kwa
120
120
  for input_name, (input_type, default_value) in interface.inputs.items():
121
121
  if input_name in kwargs:
122
122
  type_hints[input_name] = input_type
123
- elif (default_value is not None and default_value is not inspect.Signature.empty) or (
124
- default_value is None and is_optional_type(input_type)
123
+ elif (
124
+ (default_value is not None and default_value is not inspect.Signature.empty)
125
+ or (default_value is None and is_optional_type(input_type))
126
+ or input_type is None
125
127
  ):
126
128
  if default_value == NativeInterface.has_default:
127
129
  if interface._remote_defaults is None or input_name not in interface._remote_defaults:
128
130
  raise ValueError(f"Input '{input_name}' has a default value but it is not set in the interface.")
129
131
  already_converted_kwargs[input_name] = interface._remote_defaults[input_name]
132
+ elif input_type is None:
133
+ # If the type is None, we assume it's a placeholder for no type
134
+ kwargs[input_name] = None
135
+ type_hints[input_name] = NoneType
130
136
  else:
131
137
  kwargs[input_name] = default_value
132
138
  type_hints[input_name] = input_type
@@ -150,6 +156,22 @@ async def convert_from_native_to_inputs(interface: NativeInterface, *args, **kwa
150
156
  )
151
157
 
152
158
 
159
+ async def convert_from_inputs_to_native(native_interface: NativeInterface, inputs: Inputs) -> Dict[str, Any]:
160
+ """
161
+ Converts the inputs from a run definition proto to a native Python dictionary.
162
+ :param native_interface: The native interface of the task.
163
+ :param inputs: The run definition inputs proto.
164
+ :return: A dictionary of input names to their native Python values.
165
+ """
166
+ if not inputs or not inputs.proto_inputs or not inputs.proto_inputs.literals:
167
+ return {}
168
+
169
+ literals = {named_literal.name: named_literal.value for named_literal in inputs.proto_inputs.literals}
170
+ return await TypeEngine.literal_map_to_kwargs(
171
+ literals_pb2.LiteralMap(literals=literals), native_interface.get_input_types()
172
+ )
173
+
174
+
153
175
  async def convert_from_native_to_outputs(o: Any, interface: NativeInterface, task_name: str = "") -> Outputs:
154
176
  # Always make it a tuple even if it's just one item to simplify logic below
155
177
  if not isinstance(o, tuple):
flyte/_run.py CHANGED
@@ -376,9 +376,10 @@ class _Runner:
376
376
  raise err
377
377
  return outputs
378
378
 
379
- async def _run_local(self, obj: TaskTemplate[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
379
+ async def _run_local(self, obj: TaskTemplate[P, R], *args: P.args, **kwargs: P.kwargs) -> Run:
380
380
  from flyte._internal.controllers import create_controller
381
381
  from flyte._internal.controllers._local_controller import LocalController
382
+ from flyte.remote import Run
382
383
  from flyte.report import Report
383
384
 
384
385
  controller = cast(LocalController, create_controller("local"))
@@ -409,9 +410,37 @@ class _Runner:
409
410
  if obj._call_as_synchronous:
410
411
  fut = controller.submit_sync(obj, *args, **kwargs)
411
412
  awaitable = asyncio.wrap_future(fut)
412
- return await awaitable
413
+ outputs = await awaitable
413
414
  else:
414
- return await controller.submit(obj, *args, **kwargs)
415
+ outputs = await controller.submit(obj, *args, **kwargs)
416
+
417
+ class _LocalRun(Run):
418
+ def __init__(self, outputs: Tuple[Any, ...] | Any):
419
+ from flyte._protos.workflow import run_definition_pb2
420
+
421
+ self._outputs = outputs
422
+ super().__init__(
423
+ pb2=run_definition_pb2.Run(
424
+ action=run_definition_pb2.Action(
425
+ id=run_definition_pb2.ActionIdentifier(
426
+ name="a0",
427
+ run=run_definition_pb2.RunIdentifier(name="dry-run"),
428
+ )
429
+ )
430
+ )
431
+ )
432
+
433
+ @property
434
+ def url(self) -> str:
435
+ return "local-run"
436
+
437
+ def wait(self, quiet: bool = False, wait_for: Literal["terminal", "running"] = "terminal"):
438
+ pass
439
+
440
+ def outputs(self) -> R:
441
+ return cast(R, self._outputs)
442
+
443
+ return _LocalRun(outputs)
415
444
 
416
445
  @syncify
417
446
  async def run(
@@ -90,7 +90,11 @@ class TaskEnvironment(Environment):
90
90
 
91
91
  """
92
92
  cache = kwargs.pop("cache", None)
93
- reusable = kwargs.pop("reusable", None)
93
+ reusable = None
94
+ reusable_set = False
95
+ if "reusable" in kwargs:
96
+ reusable_set = True
97
+ reusable = kwargs.pop("reusable", None)
94
98
 
95
99
  # validate unknown kwargs if needed
96
100
  if kwargs:
@@ -106,7 +110,7 @@ class TaskEnvironment(Environment):
106
110
  kwargs["cache"] = cache
107
111
  if env is not None:
108
112
  kwargs["env"] = env
109
- if reusable is not None:
113
+ if reusable_set:
110
114
  kwargs["reusable"] = reusable
111
115
  if secrets is not None:
112
116
  kwargs["secrets"] = secrets
flyte/_tools.py CHANGED
@@ -25,3 +25,16 @@ def is_in_cluster() -> bool:
25
25
  if os.getenv("_UN_CLS"):
26
26
  return True
27
27
  return False
28
+
29
+
30
+ def ipywidgets_check() -> bool:
31
+ """
32
+ Check if the interface is running in IPython with ipywidgets support.
33
+ :return: True if running in IPython with ipywidgets support, False otherwise.
34
+ """
35
+ try:
36
+ import ipywidgets # noqa: F401
37
+
38
+ return True
39
+ except (ImportError, NameError):
40
+ return False
flyte/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.2.0b25'
21
- __version_tuple__ = version_tuple = (0, 2, 0, 'b25')
20
+ __version__ = version = '0.2.0b27'
21
+ __version_tuple__ = version_tuple = (0, 2, 0, 'b27')
flyte/cli/_get.py CHANGED
@@ -5,6 +5,8 @@ import rich_click as click
5
5
  from rich.console import Console
6
6
  from rich.pretty import pretty_repr
7
7
 
8
+ import flyte.remote._action
9
+
8
10
  from . import _common as common
9
11
 
10
12
 
@@ -122,17 +124,18 @@ def action(
122
124
  """
123
125
  Get all actions for a run or details for a specific action.
124
126
  """
125
- import flyte.remote as remote
126
127
 
127
128
  cfg.init(project=project, domain=domain)
128
129
 
129
130
  console = Console()
130
131
  if action_name:
131
- console.print(pretty_repr(remote.Action.get(run_name=run_name, name=action_name)))
132
+ console.print(pretty_repr(flyte.remote._action.Action.get(run_name=run_name, name=action_name)))
132
133
  else:
133
134
  # List all actions for the run
134
135
  console.print(
135
- common.get_table(f"Actions for {run_name}", remote.Action.listall(for_run_name=run_name), simple=cfg.simple)
136
+ common.get_table(
137
+ f"Actions for {run_name}", flyte.remote._action.Action.listall(for_run_name=run_name), simple=cfg.simple
138
+ )
136
139
  )
137
140
 
138
141
 
@@ -201,7 +204,7 @@ def logs(
201
204
  task.cancel()
202
205
 
203
206
  if action_name:
204
- obj = remote.Action.get(run_name=run_name, name=action_name)
207
+ obj = flyte.remote._action.Action.get(run_name=run_name, name=action_name)
205
208
  else:
206
209
  obj = remote.Run.get(run_name)
207
210
  asyncio.run(_run_log_view(obj))
@@ -269,20 +272,20 @@ def io(
269
272
  cfg.init(project=project, domain=domain)
270
273
  console = Console()
271
274
  if action_name:
272
- obj = remote.ActionDetails.get(run_name=run_name, name=action_name)
275
+ obj = flyte.remote._action.ActionDetails.get(run_name=run_name, name=action_name)
273
276
  else:
274
277
  obj = remote.RunDetails.get(run_name)
275
278
 
276
279
  async def _get_io(
277
- details: Union[remote.RunDetails, remote.ActionDetails],
278
- ) -> Tuple[remote.ActionInputs | None, remote.ActionOutputs | None | str]:
280
+ details: Union[remote.RunDetails, flyte.remote._action.ActionDetails],
281
+ ) -> Tuple[flyte.remote._action.ActionInputs | None, flyte.remote._action.ActionOutputs | None | str]:
279
282
  if inputs_only or outputs_only:
280
283
  if inputs_only:
281
284
  return await details.inputs(), None
282
285
  elif outputs_only:
283
286
  return None, await details.outputs()
284
287
  inputs = await details.inputs()
285
- outputs: remote.ActionOutputs | None | str = None
288
+ outputs: flyte.remote._action.ActionOutputs | None | str = None
286
289
  try:
287
290
  outputs = await details.outputs()
288
291
  except Exception:
flyte/remote/__init__.py CHANGED
@@ -18,9 +18,10 @@ __all__ = [
18
18
  "upload_file",
19
19
  ]
20
20
 
21
+ from ._action import Action, ActionDetails, ActionInputs, ActionOutputs
21
22
  from ._client.auth import create_channel
22
23
  from ._data import upload_dir, upload_file
23
24
  from ._project import Project
24
- from ._run import Action, ActionDetails, ActionInputs, ActionOutputs, Run, RunDetails
25
+ from ._run import Run, RunDetails
25
26
  from ._secret import Secret, SecretTypes
26
27
  from ._task import Task