metaflow 2.13.1__py2.py3-none-any.whl → 2.13.3__py2.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.
- metaflow/cards.py +1 -0
- metaflow/extension_support/plugins.py +1 -0
- metaflow/parameters.py +1 -1
- metaflow/plugins/__init__.py +13 -0
- metaflow/plugins/argo/argo_workflows.py +12 -0
- metaflow/plugins/cards/card_cli.py +7 -2
- metaflow/plugins/cards/card_modules/basic.py +56 -5
- metaflow/plugins/cards/card_modules/card.py +16 -1
- metaflow/plugins/cards/card_modules/components.py +64 -16
- metaflow/plugins/cards/card_modules/main.js +27 -25
- metaflow/plugins/cards/card_modules/test_cards.py +4 -4
- metaflow/plugins/cards/component_serializer.py +1 -1
- metaflow/plugins/pypi/micromamba.py +5 -1
- metaflow/runner/metaflow_runner.py +25 -3
- metaflow/runtime.py +18 -8
- metaflow/user_configs/config_parameters.py +23 -6
- metaflow/version.py +1 -1
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/METADATA +13 -3
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/RECORD +23 -23
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/WHEEL +1 -1
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/LICENSE +0 -0
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/entry_points.txt +0 -0
- {metaflow-2.13.1.dist-info → metaflow-2.13.3.dist-info}/top_level.txt +0 -0
metaflow/cards.py
CHANGED
metaflow/parameters.py
CHANGED
@@ -369,7 +369,7 @@ class Parameter(object):
|
|
369
369
|
# Resolve any value from configurations
|
370
370
|
self.kwargs = unpack_delayed_evaluator(self.kwargs, ignore_errors=ignore_errors)
|
371
371
|
# Do it one item at a time so errors are ignored at that level (as opposed to
|
372
|
-
# at the entire kwargs
|
372
|
+
# at the entire kwargs level)
|
373
373
|
self.kwargs = {
|
374
374
|
k: resolve_delayed_evaluator(v, ignore_errors=ignore_errors)
|
375
375
|
for k, v in self.kwargs.items()
|
metaflow/plugins/__init__.py
CHANGED
@@ -19,6 +19,11 @@ CLIS_DESC = [
|
|
19
19
|
("logs", ".logs_cli.cli"),
|
20
20
|
]
|
21
21
|
|
22
|
+
# Add additional commands to the runner here
|
23
|
+
# These will be accessed using Runner().<command>()
|
24
|
+
RUNNER_CLIS_DESC = []
|
25
|
+
|
26
|
+
|
22
27
|
from .test_unbounded_foreach_decorator import InternalTestUnboundedForeachInput
|
23
28
|
|
24
29
|
# Add new step decorators here
|
@@ -168,6 +173,14 @@ def get_plugin_cli_path():
|
|
168
173
|
return resolve_plugins("cli", path_only=True)
|
169
174
|
|
170
175
|
|
176
|
+
def get_runner_cli():
|
177
|
+
return resolve_plugins("runner_cli")
|
178
|
+
|
179
|
+
|
180
|
+
def get_runner_cli_path():
|
181
|
+
return resolve_plugins("runner_cli", path_only=True)
|
182
|
+
|
183
|
+
|
171
184
|
STEP_DECORATORS = resolve_plugins("step_decorator")
|
172
185
|
FLOW_DECORATORS = resolve_plugins("flow_decorator")
|
173
186
|
ENVIRONMENTS = resolve_plugins("environment")
|
@@ -743,6 +743,17 @@ class ArgoWorkflows(object):
|
|
743
743
|
)
|
744
744
|
}
|
745
745
|
)
|
746
|
+
try:
|
747
|
+
# Build the DAG based on the DAGNodes given by the FlowGraph for the found FlowSpec class.
|
748
|
+
_steps_info, graph_structure = self.graph.output_steps()
|
749
|
+
graph_info = {
|
750
|
+
# for the time being, we only need the graph_structure. Being mindful of annotation size limits we do not include anything extra.
|
751
|
+
"graph_structure": graph_structure
|
752
|
+
}
|
753
|
+
except Exception:
|
754
|
+
graph_info = None
|
755
|
+
|
756
|
+
dag_annotation = {"metaflow/dag": json.dumps(graph_info)}
|
746
757
|
|
747
758
|
return (
|
748
759
|
WorkflowTemplate()
|
@@ -758,6 +769,7 @@ class ArgoWorkflows(object):
|
|
758
769
|
.annotations(self._base_annotations)
|
759
770
|
.labels(self._base_labels)
|
760
771
|
.label("app.kubernetes.io/name", "metaflow-flow")
|
772
|
+
.annotations(dag_annotation)
|
761
773
|
)
|
762
774
|
.spec(
|
763
775
|
WorkflowSpec()
|
@@ -691,10 +691,15 @@ def create(
|
|
691
691
|
try:
|
692
692
|
if options is not None:
|
693
693
|
mf_card = filtered_card(
|
694
|
-
options=options,
|
694
|
+
options=options,
|
695
|
+
components=component_arr,
|
696
|
+
graph=graph_dict,
|
697
|
+
flow=ctx.obj.flow,
|
695
698
|
)
|
696
699
|
else:
|
697
|
-
mf_card = filtered_card(
|
700
|
+
mf_card = filtered_card(
|
701
|
+
components=component_arr, graph=graph_dict, flow=ctx.obj.flow
|
702
|
+
)
|
698
703
|
except TypeError as e:
|
699
704
|
if render_error_card:
|
700
705
|
mf_card = None
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import base64
|
2
2
|
import json
|
3
3
|
import os
|
4
|
-
from .card import MetaflowCard, MetaflowCardComponent
|
4
|
+
from .card import MetaflowCard, MetaflowCardComponent, with_default_component_id
|
5
5
|
from .convert_to_native_type import TaskToDict
|
6
6
|
import uuid
|
7
|
+
import inspect
|
7
8
|
|
8
9
|
ABS_DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
9
10
|
RENDER_TEMPLATE_PATH = os.path.join(ABS_DIR_PATH, "base.html")
|
@@ -236,9 +237,28 @@ class LogComponent(DefaultComponent):
|
|
236
237
|
super().__init__(title=None, subtitle=None)
|
237
238
|
self._data = data
|
238
239
|
|
240
|
+
@with_default_component_id
|
239
241
|
def render(self):
|
240
242
|
datadict = super().render()
|
241
243
|
datadict["data"] = self._data
|
244
|
+
if self.component_id is not None:
|
245
|
+
datadict["id"] = self.component_id
|
246
|
+
return datadict
|
247
|
+
|
248
|
+
|
249
|
+
class PythonCodeComponent(DefaultComponent):
|
250
|
+
|
251
|
+
type = "pythonCode"
|
252
|
+
|
253
|
+
def __init__(self, data=None):
|
254
|
+
super().__init__(title=None, subtitle=None)
|
255
|
+
self._data = data
|
256
|
+
|
257
|
+
def render(self):
|
258
|
+
datadict = super().render()
|
259
|
+
datadict["data"] = self._data
|
260
|
+
if self.component_id is not None:
|
261
|
+
datadict["id"] = self.component_id
|
242
262
|
return datadict
|
243
263
|
|
244
264
|
|
@@ -343,6 +363,7 @@ class TaskInfoComponent(MetaflowCardComponent):
|
|
343
363
|
graph=None,
|
344
364
|
components=[],
|
345
365
|
runtime=False,
|
366
|
+
flow=None,
|
346
367
|
):
|
347
368
|
self._task = task
|
348
369
|
self._only_repr = only_repr
|
@@ -352,6 +373,7 @@ class TaskInfoComponent(MetaflowCardComponent):
|
|
352
373
|
self.final_component = None
|
353
374
|
self.page_component = None
|
354
375
|
self.runtime = runtime
|
376
|
+
self.flow = flow
|
355
377
|
|
356
378
|
def render(self):
|
357
379
|
"""
|
@@ -475,6 +497,16 @@ class TaskInfoComponent(MetaflowCardComponent):
|
|
475
497
|
contents=[param_component],
|
476
498
|
).render()
|
477
499
|
|
500
|
+
step_func = getattr(self.flow, self._task.parent.id)
|
501
|
+
code_table = SectionComponent(
|
502
|
+
title="Task Code",
|
503
|
+
contents=[
|
504
|
+
TableComponent(
|
505
|
+
data=[[PythonCodeComponent(inspect.getsource(step_func)).render()]]
|
506
|
+
)
|
507
|
+
],
|
508
|
+
).render()
|
509
|
+
|
478
510
|
# Don't include parameter ids + "name" in the task artifacts
|
479
511
|
artifactlist = [
|
480
512
|
task_data_dict["data"][k]
|
@@ -500,6 +532,7 @@ class TaskInfoComponent(MetaflowCardComponent):
|
|
500
532
|
page_contents.extend(
|
501
533
|
[
|
502
534
|
metadata_table,
|
535
|
+
code_table,
|
503
536
|
parameter_table,
|
504
537
|
artifact_section,
|
505
538
|
]
|
@@ -546,7 +579,7 @@ class ErrorCard(MetaflowCard):
|
|
546
579
|
|
547
580
|
RELOAD_POLICY = MetaflowCard.RELOAD_POLICY_ONCHANGE
|
548
581
|
|
549
|
-
def __init__(self, options={}, components=[], graph=None):
|
582
|
+
def __init__(self, options={}, components=[], graph=None, **kwargs):
|
550
583
|
self._only_repr = True
|
551
584
|
self._graph = None if graph is None else transform_flow_graph(graph)
|
552
585
|
self._components = components
|
@@ -602,9 +635,17 @@ class DefaultCardJSON(MetaflowCard):
|
|
602
635
|
|
603
636
|
type = "default_json"
|
604
637
|
|
605
|
-
def __init__(
|
638
|
+
def __init__(
|
639
|
+
self,
|
640
|
+
options=dict(only_repr=True),
|
641
|
+
components=[],
|
642
|
+
graph=None,
|
643
|
+
flow=None,
|
644
|
+
**kwargs
|
645
|
+
):
|
606
646
|
self._only_repr = True
|
607
647
|
self._graph = None if graph is None else transform_flow_graph(graph)
|
648
|
+
self._flow = flow
|
608
649
|
if "only_repr" in options:
|
609
650
|
self._only_repr = options["only_repr"]
|
610
651
|
self._components = components
|
@@ -615,6 +656,7 @@ class DefaultCardJSON(MetaflowCard):
|
|
615
656
|
only_repr=self._only_repr,
|
616
657
|
graph=self._graph,
|
617
658
|
components=self._components,
|
659
|
+
flow=self._flow,
|
618
660
|
).render()
|
619
661
|
return json.dumps(final_component_dict)
|
620
662
|
|
@@ -629,9 +671,17 @@ class DefaultCard(MetaflowCard):
|
|
629
671
|
|
630
672
|
type = "default"
|
631
673
|
|
632
|
-
def __init__(
|
674
|
+
def __init__(
|
675
|
+
self,
|
676
|
+
options=dict(only_repr=True),
|
677
|
+
components=[],
|
678
|
+
graph=None,
|
679
|
+
flow=None,
|
680
|
+
**kwargs
|
681
|
+
):
|
633
682
|
self._only_repr = True
|
634
683
|
self._graph = None if graph is None else transform_flow_graph(graph)
|
684
|
+
self._flow = flow
|
635
685
|
if "only_repr" in options:
|
636
686
|
self._only_repr = options["only_repr"]
|
637
687
|
self._components = components
|
@@ -646,6 +696,7 @@ class DefaultCard(MetaflowCard):
|
|
646
696
|
graph=self._graph,
|
647
697
|
components=self._components,
|
648
698
|
runtime=runtime,
|
699
|
+
flow=self._flow,
|
649
700
|
).render()
|
650
701
|
pt = self._get_mustache()
|
651
702
|
data_dict = dict(
|
@@ -688,7 +739,7 @@ class BlankCard(MetaflowCard):
|
|
688
739
|
|
689
740
|
type = "blank"
|
690
741
|
|
691
|
-
def __init__(self, options=dict(title=""), components=[], graph=None):
|
742
|
+
def __init__(self, options=dict(title=""), components=[], graph=None, **kwargs):
|
692
743
|
self._graph = None if graph is None else transform_flow_graph(graph)
|
693
744
|
self._title = ""
|
694
745
|
if "title" in options:
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
|
+
import uuid
|
2
3
|
|
3
4
|
if TYPE_CHECKING:
|
4
5
|
import metaflow
|
@@ -66,7 +67,7 @@ class MetaflowCard(object):
|
|
66
67
|
# FIXME document runtime_data
|
67
68
|
runtime_data = None
|
68
69
|
|
69
|
-
def __init__(self, options={}, components=[], graph=None):
|
70
|
+
def __init__(self, options={}, components=[], graph=None, flow=None):
|
70
71
|
pass
|
71
72
|
|
72
73
|
def _get_mustache(self):
|
@@ -140,3 +141,17 @@ class MetaflowCardComponent(object):
|
|
140
141
|
`render` returns a string or dictionary. This class can be called on the client side to dynamically add components to the `MetaflowCard`
|
141
142
|
"""
|
142
143
|
raise NotImplementedError()
|
144
|
+
|
145
|
+
|
146
|
+
def create_component_id(component):
|
147
|
+
uuid_bit = "".join(uuid.uuid4().hex.split("-"))[:6]
|
148
|
+
return type(component).__name__.lower() + "_" + uuid_bit
|
149
|
+
|
150
|
+
|
151
|
+
def with_default_component_id(func):
|
152
|
+
def ret_func(self, *args, **kwargs):
|
153
|
+
if self.component_id is None:
|
154
|
+
self.component_id = create_component_id(self)
|
155
|
+
return func(self, *args, **kwargs)
|
156
|
+
|
157
|
+
return ret_func
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any, List, Optional, Union
|
1
|
+
from typing import Any, List, Optional, Union, Callable
|
2
2
|
from .basic import (
|
3
3
|
LogComponent,
|
4
4
|
ErrorComponent,
|
@@ -7,25 +7,13 @@ from .basic import (
|
|
7
7
|
ImageComponent,
|
8
8
|
SectionComponent,
|
9
9
|
MarkdownComponent,
|
10
|
+
PythonCodeComponent,
|
10
11
|
)
|
11
|
-
from .card import MetaflowCardComponent
|
12
|
+
from .card import MetaflowCardComponent, with_default_component_id
|
12
13
|
from .convert_to_native_type import TaskToDict, _full_classname
|
13
14
|
from .renderer_tools import render_safely
|
14
15
|
import uuid
|
15
|
-
|
16
|
-
|
17
|
-
def create_component_id(component):
|
18
|
-
uuid_bit = "".join(uuid.uuid4().hex.split("-"))[:6]
|
19
|
-
return type(component).__name__.lower() + "_" + uuid_bit
|
20
|
-
|
21
|
-
|
22
|
-
def with_default_component_id(func):
|
23
|
-
def ret_func(self, *args, **kwargs):
|
24
|
-
if self.component_id is None:
|
25
|
-
self.component_id = create_component_id(self)
|
26
|
-
return func(self, *args, **kwargs)
|
27
|
-
|
28
|
-
return ret_func
|
16
|
+
import inspect
|
29
17
|
|
30
18
|
|
31
19
|
def _warning_with_component(component, msg):
|
@@ -823,3 +811,63 @@ class VegaChart(UserComponent):
|
|
823
811
|
if self._chart_inside_table and "autosize" not in self._spec:
|
824
812
|
data["spec"]["autosize"] = "fit-x"
|
825
813
|
return data
|
814
|
+
|
815
|
+
|
816
|
+
class PythonCode(UserComponent):
|
817
|
+
"""
|
818
|
+
A component to display Python code with syntax highlighting.
|
819
|
+
|
820
|
+
Example:
|
821
|
+
```python
|
822
|
+
@card
|
823
|
+
@step
|
824
|
+
def my_step(self):
|
825
|
+
# Using code_func
|
826
|
+
def my_function():
|
827
|
+
x = 1
|
828
|
+
y = 2
|
829
|
+
return x + y
|
830
|
+
current.card.append(
|
831
|
+
PythonCode(my_function)
|
832
|
+
)
|
833
|
+
|
834
|
+
# Using code_string
|
835
|
+
code = '''
|
836
|
+
def another_function():
|
837
|
+
return "Hello World"
|
838
|
+
'''
|
839
|
+
current.card.append(
|
840
|
+
PythonCode(code_string=code)
|
841
|
+
)
|
842
|
+
```
|
843
|
+
|
844
|
+
Parameters
|
845
|
+
----------
|
846
|
+
code_func : Callable[..., Any], optional, default None
|
847
|
+
The function whose source code should be displayed.
|
848
|
+
code_string : str, optional, default None
|
849
|
+
A string containing Python code to display.
|
850
|
+
Either code_func or code_string must be provided.
|
851
|
+
"""
|
852
|
+
|
853
|
+
def __init__(
|
854
|
+
self,
|
855
|
+
code_func: Optional[Callable[..., Any]] = None,
|
856
|
+
code_string: Optional[str] = None,
|
857
|
+
):
|
858
|
+
if code_func is not None:
|
859
|
+
self._code_string = inspect.getsource(code_func)
|
860
|
+
else:
|
861
|
+
self._code_string = code_string
|
862
|
+
|
863
|
+
@with_default_component_id
|
864
|
+
@render_safely
|
865
|
+
def render(self):
|
866
|
+
if self._code_string is None:
|
867
|
+
return ErrorComponent(
|
868
|
+
"`PythonCode` component requires a `code_func` or `code_string` argument. ",
|
869
|
+
"None provided for both",
|
870
|
+
).render()
|
871
|
+
_code_component = PythonCodeComponent(self._code_string)
|
872
|
+
_code_component.component_id = self.component_id
|
873
|
+
return _code_component.render()
|