metaflow 2.13.2__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 CHANGED
@@ -8,6 +8,7 @@ from metaflow.plugins.cards.card_modules.components import (
8
8
  Markdown,
9
9
  VegaChart,
10
10
  ProgressBar,
11
+ PythonCode,
11
12
  )
12
13
  from metaflow.plugins.cards.card_modules.basic import (
13
14
  DefaultCard,
@@ -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, components=component_arr, graph=graph_dict
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(components=component_arr, graph=graph_dict)
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__(self, options=dict(only_repr=True), components=[], graph=None):
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__(self, options=dict(only_repr=True), components=[], graph=None):
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()