pyglove 0.4.5.dev202410100808__py3-none-any.whl → 0.4.5.dev202410160809__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.
@@ -15,13 +15,14 @@
15
15
 
16
16
  import inspect
17
17
  import re
18
- from typing import Any, Dict, Iterable, Optional, Sequence, Set, Union
18
+ from typing import Any, Callable, Dict, Iterable, Optional, Sequence, Union
19
19
 
20
20
  from pyglove.core import object_utils
21
21
  from pyglove.core.views.html import base
22
22
 
23
23
 
24
24
  KeyPath = object_utils.KeyPath
25
+ KeyPathSet = object_utils.KeyPathSet
25
26
  Html = base.Html
26
27
  HtmlView = base.HtmlView
27
28
 
@@ -37,6 +38,40 @@ class HtmlTreeView(HtmlView):
37
38
  class Extension(HtmlView.Extension):
38
39
  """The base class for extensions for HtmlTreeView."""
39
40
 
41
+ #
42
+ # Default extension-level rendering options overrides.
43
+ #
44
+
45
+ def _html_tree_view_special_keys(self) -> Sequence[str]:
46
+ """Returns the special keys to display (at the immediate child level)."""
47
+ return []
48
+
49
+ def _html_tree_view_include_keys(self) -> Optional[Sequence[str]]:
50
+ """Returns the keys to include (at the immediate child level)."""
51
+ return None
52
+
53
+ def _html_tree_view_exclude_keys(self) -> Sequence[str]:
54
+ """Returns the keys to include (at the immediate child level)."""
55
+ return []
56
+
57
+ def _html_tree_view_uncollapse_level(self) -> Optional[int]:
58
+ """Returns the level of the subtree to uncollapse.
59
+
60
+ Returns:
61
+ The level of subtree to uncollapse. If None, the subtree will be fully
62
+ expanded. Please note that the uncollapsed subtree will show only when
63
+ current node is uncollapsed.
64
+ """
65
+ return 1
66
+
67
+ def _html_tree_view_uncollapse(self) -> KeyPathSet:
68
+ """Returns the node paths (relative to current node) to uncollapse."""
69
+ return KeyPathSet()
70
+
71
+ #
72
+ # Default behavior overrides.
73
+ #
74
+
40
75
  def _html_tree_view_render(
41
76
  self,
42
77
  *,
@@ -48,6 +83,10 @@ class HtmlTreeView(HtmlView):
48
83
  special_keys: Optional[Sequence[Union[int, str]]] = None,
49
84
  include_keys: Optional[Iterable[Union[int, str]]] = None,
50
85
  exclude_keys: Optional[Iterable[Union[int, str]]] = None,
86
+ collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
87
+ uncollapse: Union[
88
+ KeyPathSet, base.NodeFilter, None
89
+ ] = HtmlView.PresetArgValue(None),
51
90
  filter: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None), # pylint: disable=redefined-builtin
52
91
  highlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
53
92
  lowlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
@@ -55,10 +94,6 @@ class HtmlTreeView(HtmlView):
55
94
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
56
95
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
57
96
  enable_key_tooltip: bool = HtmlView.PresetArgValue(True),
58
- collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
59
- uncollapse: Union[
60
- Iterable[Union[KeyPath, str]], base.NodeFilter, None
61
- ] = HtmlView.PresetArgValue(None),
62
97
  **kwargs,
63
98
  ) -> Html:
64
99
  """Returns the topmost HTML representation of the object.
@@ -73,6 +108,10 @@ class HtmlTreeView(HtmlView):
73
108
  level).
74
109
  include_keys: The keys to include (at the immediate child level).
75
110
  exclude_keys: The keys to exclude (at the immediate child level).
111
+ collapse_level: The level to collapse the tree (relative to this node).
112
+ uncollapse: A key path set (relative to root_path) for the nodes to
113
+ uncollapse. or a function with signature (path, value, parent) -> bool
114
+ to filter nodes to uncollapse.
76
115
  filter: A function with signature (path, value, parent) -> include
77
116
  to determine whether to include a field (at all levels).
78
117
  highlight: A function with signature (path, value, parent) -> bool
@@ -85,10 +124,6 @@ class HtmlTreeView(HtmlView):
85
124
  max_summary_len_for_str: The maximum length of the string to display.
86
125
  enable_summary_tooltip: Whether to enable the tooltip for the summary.
87
126
  enable_key_tooltip: Whether to enable the tooltip for the key.
88
- collapse_level: The level to collapse the tree
89
- uncollapse: A set of key paths for the nodes to uncollapse. or a
90
- function with signature (path, value, parent) -> bool to determine
91
- whether to uncollapse a node.
92
127
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
93
128
 
94
129
  Returns:
@@ -122,7 +157,6 @@ class HtmlTreeView(HtmlView):
122
157
  name: Optional[str],
123
158
  parent: Any,
124
159
  root_path: KeyPath,
125
- css_class: Optional[Sequence[str]] = None,
126
160
  title: Union[str, Html, None] = None,
127
161
  enable_summary: Optional[bool] = HtmlView.PresetArgValue(None),
128
162
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
@@ -136,7 +170,6 @@ class HtmlTreeView(HtmlView):
136
170
  name: The name of the object.
137
171
  parent: The parent of the object.
138
172
  root_path: The key path of the object relative to the root.
139
- css_class: The CSS classes to add to the root element
140
173
  title: The title of the summary.
141
174
  enable_summary: Whether to enable the summary. If None, summary will
142
175
  be enabled for complex types or when string exceeds
@@ -156,7 +189,6 @@ class HtmlTreeView(HtmlView):
156
189
  name=name,
157
190
  parent=parent,
158
191
  root_path=root_path,
159
- css_class=css_class,
160
192
  title=title,
161
193
  enable_summary=enable_summary,
162
194
  max_summary_len_for_str=max_summary_len_for_str,
@@ -174,16 +206,16 @@ class HtmlTreeView(HtmlView):
174
206
  special_keys: Optional[Sequence[Union[int, str]]] = None,
175
207
  include_keys: Optional[Iterable[Union[int, str]]] = None,
176
208
  exclude_keys: Optional[Iterable[Union[int, str]]] = None,
209
+ collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
210
+ uncollapse: Union[
211
+ KeyPathSet, base.NodeFilter, None
212
+ ] = HtmlView.PresetArgValue(None),
177
213
  filter: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None), # pylint: disable=redefined-builtin
178
214
  highlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
179
215
  lowlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
180
216
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
181
217
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
182
218
  enable_key_tooltip: bool = HtmlView.PresetArgValue(True),
183
- collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
184
- uncollapse: Union[
185
- Iterable[Union[KeyPath, str]], base.NodeFilter, None
186
- ] = HtmlView.PresetArgValue(None),
187
219
  **kwargs,
188
220
  ) -> Html:
189
221
  """Returns the main content for the object.
@@ -197,6 +229,10 @@ class HtmlTreeView(HtmlView):
197
229
  level).
198
230
  include_keys: The keys to include (at the immediate child level).
199
231
  exclude_keys: The keys to exclude (at the immediate child level).
232
+ collapse_level: The level to collapse the tree (relative to this node).
233
+ uncollapse: A key path set (relative to root_path) for the nodes to
234
+ uncollapse. or a function with signature (path, value, parent) -> bool
235
+ to filter nodes to uncollapse.
200
236
  filter: A function with signature (path, value, parent) -> include
201
237
  to determine whether to include a field (at all levels).
202
238
  highlight: A function with signature (path, value, parent) -> bool
@@ -206,8 +242,6 @@ class HtmlTreeView(HtmlView):
206
242
  max_summary_len_for_str: The maximum length of the string to display.
207
243
  enable_summary_tooltip: Whether to enable the tooltip for the summary.
208
244
  enable_key_tooltip: Whether to enable the key tooltip.
209
- collapse_level: The level to collapse the tree
210
- uncollapse: The paths to uncollapse.
211
245
  **kwargs: Additional keyword arguments passed from `pg.to_html`. These
212
246
  arguments may be handled by the user logic but not the general
213
247
  HtmlTreeView.
@@ -273,11 +307,14 @@ class HtmlTreeView(HtmlView):
273
307
  name: Optional[str] = None,
274
308
  parent: Any = None,
275
309
  root_path: Optional[KeyPath] = None,
276
- css_class: Optional[Sequence[str]] = None,
277
310
  title: Union[str, Html, None] = None,
278
311
  special_keys: Optional[Sequence[Union[int, str]]] = None,
279
312
  include_keys: Optional[Iterable[Union[int, str]]] = None,
280
313
  exclude_keys: Optional[Iterable[Union[int, str]]] = None,
314
+ collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
315
+ uncollapse: Union[
316
+ KeyPathSet, base.NodeFilter, None
317
+ ] = HtmlView.PresetArgValue(None),
281
318
  filter: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None), # pylint: disable=redefined-builtin
282
319
  highlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
283
320
  lowlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
@@ -285,10 +322,6 @@ class HtmlTreeView(HtmlView):
285
322
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
286
323
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
287
324
  enable_key_tooltip: bool = HtmlView.PresetArgValue(True),
288
- collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
289
- uncollapse: Union[
290
- Iterable[Union[KeyPath, str]], base.NodeFilter, None
291
- ] = HtmlView.PresetArgValue(None),
292
325
  **kwargs
293
326
  ) -> Html:
294
327
  """Renders the entire HTML tree view for the value.
@@ -298,11 +331,14 @@ class HtmlTreeView(HtmlView):
298
331
  name: The name of the value.
299
332
  parent: The parent of the value.
300
333
  root_path: The root path of the value.
301
- css_class: The CSS classes to add to the root element
302
334
  title: The title of the summary.
303
335
  special_keys: The special keys to display (at the immediate child level).
304
336
  include_keys: The keys to include (at the immediate child level).
305
337
  exclude_keys: The keys to exclude (at the immediate child level).
338
+ collapse_level: The level to collapse the tree (relative to this node).
339
+ uncollapse: A key path set (relative to root_path) for the nodes to
340
+ uncollapse. or a function with signature (path, value, parent) -> bool
341
+ to filter nodes to uncollapse.
306
342
  filter: A function with signature (path, value, parent) -> include
307
343
  to determine whether to include a field (at all levels).
308
344
  highlight: A function with signature (path, value, parent) -> bool
@@ -315,15 +351,31 @@ class HtmlTreeView(HtmlView):
315
351
  max_summary_len_for_str: The maximum length of the string to display.
316
352
  enable_summary_tooltip: Whether to enable the tooltip for the summary.
317
353
  enable_key_tooltip: Whether to enable the key tooltip.
318
- collapse_level: The level to collapse the tree.
319
- uncollapse: The paths to uncollapse.
320
354
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
321
355
 
322
356
  Returns:
323
357
  The rendered HTML.
324
358
  """
325
359
  root_path = root_path or KeyPath()
326
- uncollapse = self.normalize_uncollapse(uncollapse)
360
+ uncollapse = self.init_uncollapse(uncollapse)
361
+
362
+ child_collapse_level = collapse_level
363
+ if isinstance(value, HtmlTreeView.Extension):
364
+ subtree_uncollapse_level = value._html_tree_view_uncollapse_level() # pylint: disable=protected-access
365
+
366
+ # If the extension has child levels to uncollapse, honor them above the
367
+ # collapse level passed from the root. However, we can see the
368
+ # uncollapsed extension subtree only when the extension's parent node is
369
+ # uncollapsed.
370
+ child_collapse_level = self.max_collapse_level(
371
+ collapse_level, subtree_uncollapse_level, root_path
372
+ )
373
+ if not callable(uncollapse):
374
+ extension_uncollapse = value._html_tree_view_uncollapse().copy() # pylint: disable=protected-access
375
+ if extension_uncollapse:
376
+ extension_uncollapse.rebase(root_path)
377
+ uncollapse = uncollapse.union(extension_uncollapse)
378
+
327
379
  summary = self.summary(
328
380
  value,
329
381
  name=name,
@@ -340,21 +392,25 @@ class HtmlTreeView(HtmlView):
340
392
  name=name,
341
393
  parent=parent,
342
394
  root_path=root_path,
343
- css_class=css_class if summary is None else None,
344
395
  filter=filter,
345
396
  special_keys=special_keys,
346
397
  include_keys=include_keys,
347
398
  exclude_keys=exclude_keys,
399
+ collapse_level=child_collapse_level,
400
+ uncollapse=uncollapse,
348
401
  max_summary_len_for_str=max_summary_len_for_str,
349
402
  enable_summary_tooltip=enable_summary_tooltip,
350
403
  enable_key_tooltip=enable_key_tooltip,
351
- collapse_level=collapse_level,
352
- uncollapse=uncollapse,
353
404
  **kwargs,
354
405
  )
406
+ extension_style = (
407
+ value._html_style() if isinstance(value, HtmlView.Extension) else [] # pylint: disable=protected-access
408
+ )
409
+
355
410
  if summary is None:
356
411
  content = Html.from_value(content)
357
412
  assert content is not None
413
+ content.add_style(*extension_style)
358
414
  return content
359
415
 
360
416
  collapse_view = self.should_collapse(
@@ -371,7 +427,7 @@ class HtmlTreeView(HtmlView):
371
427
  css_class=[
372
428
  'pyglove',
373
429
  self.css_class_name(value),
374
- ] + (css_class or []),
430
+ ],
375
431
  ).add_style(
376
432
  """
377
433
  /* Value details styles. */
@@ -393,29 +449,23 @@ class HtmlTreeView(HtmlView):
393
449
  .lowlight {
394
450
  opacity: 0.2;
395
451
  }
396
- """
452
+ """,
453
+ *extension_style,
397
454
  )
398
455
 
399
- def normalize_uncollapse(
456
+ def init_uncollapse(
400
457
  self,
401
458
  uncollapse: Union[
402
459
  Iterable[Union[KeyPath, str]], base.NodeFilter, None
403
460
  ] = HtmlView.PresetArgValue(None),
404
- ) -> Union[None, Set[KeyPath], base.NodeFilter]:
461
+ ) -> Union[KeyPathSet, base.NodeFilter]:
405
462
  """Normalize the uncollapse argument."""
406
463
  if uncollapse is None:
407
- return None
408
- elif isinstance(uncollapse, set) or callable(uncollapse):
464
+ return KeyPathSet()
465
+ elif callable(uncollapse):
409
466
  return uncollapse
410
467
  else:
411
- expanded = set()
412
- for path in uncollapse:
413
- path = object_utils.KeyPath.from_value(path)
414
- expanded.add(path)
415
- while path:
416
- expanded.add(path.parent)
417
- path = path.parent
418
- return expanded
468
+ return KeyPathSet.from_value(uncollapse, include_intermediate=True)
419
469
 
420
470
  def should_collapse(
421
471
  self,
@@ -423,16 +473,12 @@ class HtmlTreeView(HtmlView):
423
473
  root_path: KeyPath,
424
474
  parent: Any,
425
475
  collapse_level: Optional[int] = 0,
426
- uncollapse: Union[
427
- Set[Union[KeyPath, str]], base.NodeFilter, None
428
- ] = None,
476
+ uncollapse: Union[KeyPathSet, base.NodeFilter] = None,
429
477
  ) -> bool:
430
478
  """Returns whether the object should be collapsed."""
431
479
  if collapse_level is None or root_path.depth < collapse_level:
432
480
  return False
433
- if uncollapse is None:
434
- return True
435
- elif callable(uncollapse):
481
+ if callable(uncollapse):
436
482
  return not uncollapse(root_path, value, parent)
437
483
  else:
438
484
  return root_path not in uncollapse
@@ -468,7 +514,6 @@ class HtmlTreeView(HtmlView):
468
514
  name: Optional[str] = None,
469
515
  parent: Any = None,
470
516
  root_path: Optional[KeyPath] = None,
471
- css_class: Optional[Sequence[str]] = None,
472
517
  title: Union[str, Html, None] = None,
473
518
  enable_summary: Optional[bool] = HtmlView.PresetArgValue(None),
474
519
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
@@ -482,7 +527,6 @@ class HtmlTreeView(HtmlView):
482
527
  name: The name of the value.
483
528
  parent: The parent of the value.
484
529
  root_path: The root path of the value.
485
- css_class: The CSS classes to add to the root element
486
530
  title: The title of the summary.
487
531
  enable_summary: Whether to enable the summary. If None, summary will
488
532
  be enabled for complex types or when string exceeds
@@ -542,7 +586,6 @@ class HtmlTreeView(HtmlView):
542
586
  **kwargs,
543
587
  ) if enable_summary_tooltip else None,
544
588
  ],
545
- css_class=css_class,
546
589
  ).add_style(
547
590
  """
548
591
  /* Summary styles. */
@@ -583,7 +626,7 @@ class HtmlTreeView(HtmlView):
583
626
  name: Optional[str] = None,
584
627
  parent: Any,
585
628
  root_path: Optional[KeyPath] = None,
586
- css_class: Optional[Sequence[str]] = None,
629
+ css_class: Union[str, Sequence[str], None] = None,
587
630
  key_color: Optional[str] = None,
588
631
  enable_tooltip: bool = HtmlView.PresetArgValue(True),
589
632
  **kwargs
@@ -595,7 +638,7 @@ class HtmlTreeView(HtmlView):
595
638
  name: The name of the value.
596
639
  parent: The parent value of the key.
597
640
  root_path: The root path of the value.
598
- css_class: The CSS classes to add to the root element.
641
+ css_class: Additional CSS classes to add to the HTML element.
599
642
  key_color: The color of the key.
600
643
  enable_tooltip: Whether to enable the tooltip.
601
644
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
@@ -610,7 +653,11 @@ class HtmlTreeView(HtmlView):
610
653
  [
611
654
  str(key),
612
655
  ],
613
- css_class=['object_key'] + (css_class or []),
656
+ css_class=[
657
+ 'object_key',
658
+ type(key).__name__,
659
+ css_class,
660
+ ],
614
661
  style=dict(
615
662
  color=key_color,
616
663
  )
@@ -634,26 +681,26 @@ class HtmlTreeView(HtmlView):
634
681
  visibility: visible;
635
682
  background-color: darkblue;
636
683
  }
637
- .complex_value .object_key{
684
+ .object_key.str {
638
685
  color: gray;
639
686
  border: 1px solid lightgray;
640
687
  background-color: ButtonFace;
641
688
  border-radius: 0.2em;
642
689
  padding: 0.3em;
643
690
  }
644
- .complex_value.list .object_key{
691
+ .object_key.int::before{
692
+ content: '[';
693
+ }
694
+ .object_key.int::after{
695
+ content: ']';
696
+ }
697
+ .object_key.int{
645
698
  border: 0;
646
699
  color: lightgray;
647
700
  background-color: transparent;
648
701
  border-radius: 0;
649
702
  padding: 0;
650
703
  }
651
- .complex_value.list .object_key::before{
652
- content: '[';
653
- }
654
- .complex_value.list .object_key::after{
655
- content: ']';
656
- }
657
704
  """
658
705
  )
659
706
 
@@ -665,20 +712,19 @@ class HtmlTreeView(HtmlView):
665
712
  name: Optional[str] = None,
666
713
  parent: Any = None,
667
714
  root_path: Optional[KeyPath] = None,
668
- css_class: Optional[Sequence[str]] = None,
669
715
  special_keys: Optional[Sequence[Union[int, str]]] = None,
670
716
  include_keys: Optional[Iterable[Union[int, str]]] = None,
671
717
  exclude_keys: Optional[Iterable[Union[int, str]]] = None,
718
+ collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
719
+ uncollapse: Union[
720
+ KeyPathSet, base.NodeFilter, None
721
+ ] = HtmlView.PresetArgValue(None),
672
722
  filter: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None), # pylint: disable=redefined-builtin
673
723
  highlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
674
724
  lowlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
675
725
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
676
726
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
677
727
  enable_key_tooltip: bool = HtmlView.PresetArgValue(True),
678
- collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
679
- uncollapse: Union[
680
- Iterable[Union[KeyPath, str]], base.NodeFilter, None
681
- ] = HtmlView.PresetArgValue(None),
682
728
  **kwargs
683
729
  ) -> Html:
684
730
  """Renders the main content for the value.
@@ -688,10 +734,13 @@ class HtmlTreeView(HtmlView):
688
734
  name: The name of the value.
689
735
  parent: The parent of the value.
690
736
  root_path: The root path of the value.
691
- css_class: Additional CSS classes for root element.
692
737
  special_keys: The special keys to display (at the immediate child level).
693
738
  include_keys: The keys to include (at the immediate child level).
694
739
  exclude_keys: The keys to exclude (at the immediate child level).
740
+ collapse_level: The level to collapse the tree (relative to this node).
741
+ uncollapse: A key path set (relative to root_path) for the nodes to
742
+ uncollapse. or a function with signature (path, value, parent) -> bool
743
+ to filter nodes to uncollapse.
695
744
  filter: A function with signature (path, value, parent) -> include
696
745
  to determine whether to include a field (at all levels).
697
746
  highlight: A function with signature (path, value, parent) -> bool
@@ -701,8 +750,6 @@ class HtmlTreeView(HtmlView):
701
750
  max_summary_len_for_str: The maximum length of the string to display.
702
751
  enable_summary_tooltip: Whether to enable the summary tooltip.
703
752
  enable_key_tooltip: Whether to enable the key tooltip.
704
- collapse_level: The level of the tree to collapse.
705
- uncollapse: The keys to uncollapse.
706
753
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
707
754
 
708
755
  Returns:
@@ -715,25 +762,24 @@ class HtmlTreeView(HtmlView):
715
762
  else:
716
763
  return self.simple_value(
717
764
  value, name=name, parent=parent, root_path=root_path,
718
- css_class=css_class, max_summary_len_for_str=max_summary_len_for_str
765
+ max_summary_len_for_str=max_summary_len_for_str
719
766
  )
720
767
  return self.complex_value(
721
768
  items,
722
769
  name=name,
723
770
  parent=value,
724
771
  root_path=root_path or KeyPath(),
725
- css_class=css_class,
726
772
  special_keys=special_keys,
727
773
  include_keys=include_keys,
728
774
  exclude_keys=exclude_keys,
775
+ collapse_level=collapse_level,
776
+ uncollapse=uncollapse,
729
777
  filter=filter,
730
778
  highlight=highlight,
731
779
  lowlight=lowlight,
732
780
  max_summary_len_for_str=max_summary_len_for_str,
733
781
  enable_summary_tooltip=enable_summary_tooltip,
734
782
  enable_key_tooltip=enable_key_tooltip,
735
- collapse_level=collapse_level,
736
- uncollapse=uncollapse,
737
783
  **kwargs,
738
784
  )
739
785
 
@@ -744,7 +790,7 @@ class HtmlTreeView(HtmlView):
744
790
  name: Optional[str] = None,
745
791
  parent: Any = None,
746
792
  root_path: Optional[KeyPath] = None,
747
- css_class: Optional[Sequence[str]] = None,
793
+ css_class: Union[str, Sequence[str], None] = None,
748
794
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
749
795
  ) -> Html:
750
796
  """Renders a simple value.
@@ -754,7 +800,7 @@ class HtmlTreeView(HtmlView):
754
800
  name: The name of the value.
755
801
  parent: The parent of the value.
756
802
  root_path: The root path of the value.
757
- css_class: Additional CSS classes for root span.
803
+ css_class: Additional CSS classes to add to the HTML element.
758
804
  max_summary_len_for_str: The maximum length of the string to display.
759
805
 
760
806
  Returns:
@@ -778,9 +824,11 @@ class HtmlTreeView(HtmlView):
778
824
  [
779
825
  Html.escape(value_repr),
780
826
  ],
781
- css_class=['simple_value', self.css_class_name(value)] + (
782
- css_class or []
783
- ),
827
+ css_class=[
828
+ 'simple_value',
829
+ self.css_class_name(value),
830
+ css_class,
831
+ ],
784
832
  ).add_style(
785
833
  """
786
834
  /* Simple value styles. */
@@ -805,36 +853,48 @@ class HtmlTreeView(HtmlView):
805
853
  self,
806
854
  kv: Dict[Union[int, str], Any],
807
855
  *,
856
+ parent: Any,
857
+ root_path: KeyPath,
808
858
  name: Optional[str] = None,
809
- parent: Any = None,
810
- root_path: Optional[KeyPath] = None,
811
- css_class: Optional[Sequence[str]] = None,
859
+ css_class: Union[str, Sequence[str], None] = None,
860
+ render_key_fn: Optional[Callable[..., Html]] = None,
861
+ render_value_fn: Optional[Callable[..., Html]] = None,
812
862
  special_keys: Optional[Sequence[Union[int, str]]] = None,
813
863
  include_keys: Optional[Iterable[Union[int, str]]] = None,
814
864
  exclude_keys: Optional[Iterable[Union[int, str]]] = None,
865
+ collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
866
+ uncollapse: Union[
867
+ KeyPathSet, base.NodeFilter, None
868
+ ] = HtmlView.PresetArgValue(None),
815
869
  filter: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None), # pylint: disable=redefined-builtin
816
870
  highlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
817
871
  lowlight: Optional[base.NodeFilter] = HtmlView.PresetArgValue(None),
818
872
  max_summary_len_for_str: int = HtmlView.PresetArgValue(40),
819
873
  enable_summary_tooltip: bool = HtmlView.PresetArgValue(True),
820
874
  enable_key_tooltip: bool = HtmlView.PresetArgValue(True),
821
- collapse_level: Optional[int] = HtmlView.PresetArgValue(1),
822
- uncollapse: Union[
823
- Iterable[Union[KeyPath, str]], base.NodeFilter, None
824
- ] = HtmlView.PresetArgValue(None),
825
875
  **kwargs,
826
876
  ) -> Html:
827
877
  """Renders a list of key-value pairs.
828
878
 
829
879
  Args:
830
880
  kv: The key-value pairs to render.
831
- name: The name of the value.
832
881
  parent: The parent value of the key-value pairs.
833
882
  root_path: The root path of the value.
834
- css_class: Additional CSS classes for root div.
883
+ name: The name of the value.
884
+ css_class: Additional CSS classes to add to the HTML element.
885
+ render_key_fn: A function to render the key. The function has the
886
+ same signature as `HtmlTreeView.object_key`.
887
+ If None, `HtmlTreeView.object_key` will be used to render the key.
888
+ render_value_fn: A function to render the value. The function has the
889
+ same signature as `HtmlTreeView.render`.
890
+ If None, `HtmlTreeView.render` will be used to render child value.
835
891
  special_keys: The special keys to display (at the immediate child level).
836
892
  include_keys: The keys to include (at the immediate child level).
837
893
  exclude_keys: The keys to exclude (at the immediate child level).
894
+ collapse_level: The level to collapse the tree (relative to this node).
895
+ uncollapse: A key path set (relative to root_path) for the nodes to
896
+ uncollapse. or a function with signature (path, value, parent) -> bool
897
+ to filter nodes to uncollapse.
838
898
  filter: A function with signature (path, value, parent) -> include
839
899
  to determine whether to include.
840
900
  highlight: A function with signature (path, value, parent) -> bool
@@ -844,18 +904,26 @@ class HtmlTreeView(HtmlView):
844
904
  max_summary_len_for_str: The maximum length of the string to display.
845
905
  enable_summary_tooltip: Whether to enable the summary tooltip.
846
906
  enable_key_tooltip: Whether to enable the key tooltip.
847
- collapse_level: The level of the tree to collapse.
848
- uncollapse: The keys to uncollapse.
849
907
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
850
908
 
851
909
  Returns:
852
910
  The rendered HTML as the key-value pairs.
853
911
  """
854
912
  del name
913
+ root_path = root_path or KeyPath()
914
+ uncollapse = self.init_uncollapse(uncollapse)
915
+
916
+ if isinstance(parent, HtmlTreeView.Extension):
917
+ special_keys = special_keys or parent._html_tree_view_special_keys() # pylint: disable=protected-access
918
+ include_keys = include_keys or parent._html_tree_view_include_keys() # pylint: disable=protected-access
919
+ exclude_keys = exclude_keys or parent._html_tree_view_exclude_keys() # pylint: disable=protected-access
920
+
855
921
  special_keys = special_keys or []
856
922
  include_keys = set(include_keys or [])
857
923
  exclude_keys = set(exclude_keys or [])
858
- uncollapse = self.normalize_uncollapse(uncollapse)
924
+
925
+ render_key_fn = render_key_fn or self.object_key
926
+ render_value_fn = render_value_fn or self.render
859
927
 
860
928
  s = Html()
861
929
  if kv:
@@ -873,37 +941,40 @@ class HtmlTreeView(HtmlView):
873
941
  if k in include_keys and k in kv:
874
942
  child_path = root_path + k
875
943
  v = kv[k]
876
-
877
- child_css_class = [
878
- 'special_value',
879
- (
880
- 'highlight' if highlight
881
- and highlight(child_path, v, parent) else None
882
- ),
883
- (
884
- 'lowlight' if lowlight
885
- and lowlight(child_path, v, parent) else None
886
- )
887
- ]
888
944
  s.write(
889
- self.render(
890
- value=v,
891
- name=k,
892
- parent=v,
893
- root_path=child_path,
894
- css_class=child_css_class,
895
- filter=filter,
896
- special_keys=None,
897
- include_keys=None,
898
- exclude_keys=None,
899
- highlight=highlight,
900
- lowlight=lowlight,
901
- max_summary_len_for_str=max_summary_len_for_str,
902
- enable_summary_tooltip=enable_summary_tooltip,
903
- enable_key_tooltip=enable_key_tooltip,
904
- collapse_level=collapse_level,
905
- uncollapse=uncollapse,
906
- **kwargs
945
+ Html.element(
946
+ 'div',
947
+ [
948
+ render_value_fn(
949
+ value=v,
950
+ name=k,
951
+ parent=parent,
952
+ root_path=child_path,
953
+ filter=filter,
954
+ special_keys=None,
955
+ include_keys=None,
956
+ exclude_keys=None,
957
+ collapse_level=collapse_level,
958
+ uncollapse=uncollapse,
959
+ highlight=highlight,
960
+ lowlight=lowlight,
961
+ max_summary_len_for_str=max_summary_len_for_str,
962
+ enable_summary_tooltip=enable_summary_tooltip,
963
+ enable_key_tooltip=enable_key_tooltip,
964
+ **kwargs
965
+ )
966
+ ],
967
+ css_class=[
968
+ 'special_value',
969
+ (
970
+ 'highlight' if highlight
971
+ and highlight(child_path, v, parent) else None
972
+ ),
973
+ (
974
+ 'lowlight' if lowlight
975
+ and lowlight(child_path, v, parent) else None
976
+ )
977
+ ],
907
978
  )
908
979
  )
909
980
  include_keys.remove(k)
@@ -914,45 +985,51 @@ class HtmlTreeView(HtmlView):
914
985
  if k not in include_keys:
915
986
  continue
916
987
  child_path = root_path + k
917
- key = self.object_key(
918
- key=k, parent=v, root_path=child_path,
988
+ key_cell = render_key_fn(
989
+ key=k,
990
+ parent=parent,
991
+ root_path=child_path,
919
992
  enable_tooltip=enable_key_tooltip,
920
993
  )
921
- child_css_class = [
922
- (
923
- 'highlight' if highlight and highlight(child_path, v, parent)
924
- else None
925
- ),
926
- (
927
- 'lowlight' if lowlight and lowlight(child_path, v, parent)
928
- else None
929
- )
930
- ]
931
- value = self.render(
932
- value=v,
933
- name=None,
934
- parent=v,
935
- root_path=child_path,
936
- css_class=child_css_class,
937
- special_keys=None,
938
- include_keys=None,
939
- exclude_keys=None,
940
- filter=filter,
941
- highlight=highlight,
942
- lowlight=lowlight,
943
- max_summary_len_for_str=max_summary_len_for_str,
944
- enable_summary_tooltip=enable_summary_tooltip,
945
- enable_key_tooltip=enable_key_tooltip,
946
- collapse_level=collapse_level,
947
- uncollapse=uncollapse,
948
- **kwargs,
994
+ value_cell = Html.element(
995
+ 'div',
996
+ [
997
+ render_value_fn(
998
+ value=v,
999
+ name=None,
1000
+ parent=parent,
1001
+ root_path=child_path,
1002
+ special_keys=None,
1003
+ include_keys=None,
1004
+ exclude_keys=None,
1005
+ collapse_level=collapse_level,
1006
+ uncollapse=uncollapse,
1007
+ filter=filter,
1008
+ highlight=highlight,
1009
+ lowlight=lowlight,
1010
+ max_summary_len_for_str=max_summary_len_for_str,
1011
+ enable_summary_tooltip=enable_summary_tooltip,
1012
+ enable_key_tooltip=enable_key_tooltip,
1013
+ **kwargs,
1014
+ )
1015
+ ],
1016
+ css_class=[
1017
+ (
1018
+ 'highlight' if highlight
1019
+ and highlight(child_path, v, parent) else None
1020
+ ),
1021
+ (
1022
+ 'lowlight' if lowlight
1023
+ and lowlight(child_path, v, parent) else None
1024
+ )
1025
+ ],
949
1026
  )
950
1027
  s.write(
951
1028
  Html.element(
952
1029
  'tr',
953
1030
  [
954
- '<td>', key, '</td>',
955
- '<td>', value, '</td>',
1031
+ '<td>', key_cell, '</td>',
1032
+ '<td>', value_cell, '</td>',
956
1033
  ],
957
1034
  )
958
1035
  )
@@ -962,9 +1039,11 @@ class HtmlTreeView(HtmlView):
962
1039
  return Html.element(
963
1040
  'div',
964
1041
  [s],
965
- css_class=['complex_value', self.css_class_name(parent)] + (
966
- css_class or []
967
- ),
1042
+ css_class=[
1043
+ 'complex_value',
1044
+ self.css_class_name(parent),
1045
+ css_class,
1046
+ ]
968
1047
  ).add_style(
969
1048
  """
970
1049
  /* Complex value styles. */
@@ -985,7 +1064,6 @@ class HtmlTreeView(HtmlView):
985
1064
  name: Optional[str] = None,
986
1065
  parent: Any = None,
987
1066
  root_path: Optional[KeyPath] = None,
988
- css_class: Optional[Sequence[str]] = None,
989
1067
  content: Union[str, Html, None] = HtmlView.PresetArgValue(None),
990
1068
  **kwargs
991
1069
  ) -> Html:
@@ -996,7 +1074,6 @@ class HtmlTreeView(HtmlView):
996
1074
  name: The name of the value.
997
1075
  parent: The parent value of the key-value pairs.
998
1076
  root_path: The root path of the value.
999
- css_class: Additional CSS classes for the tooltip span.
1000
1077
  content: The content of the tooltip. If None, the formatted value will be
1001
1078
  used as the content.
1002
1079
  **kwargs: Additional keyword arguments passed from `pg.to_html`.
@@ -1021,7 +1098,7 @@ class HtmlTreeView(HtmlView):
1021
1098
  return Html.element(
1022
1099
  'span',
1023
1100
  [content],
1024
- css_class=['tooltip'] + (css_class or []),
1101
+ css_class=['tooltip', self.css_class_name(value)],
1025
1102
  ).add_style(
1026
1103
  """
1027
1104
  /* Tooltip styles. */
@@ -1040,11 +1117,23 @@ class HtmlTreeView(HtmlView):
1040
1117
  )
1041
1118
 
1042
1119
  @staticmethod
1043
- def css_class_name(value: Any) -> str:
1120
+ def css_class_name(value: Any) -> Optional[str]:
1044
1121
  """Returns the CSS class name for the value."""
1122
+ if isinstance(value, HtmlTreeView.Extension):
1123
+ return Html.concate(value._html_element_class()) # pylint: disable=protected-access
1045
1124
  value = value if inspect.isclass(value) else type(value)
1046
- class_name = value.__name__
1047
- return _REGEX_CAMEL_TO_SNAKE.sub('-', class_name).lower()
1125
+ return object_utils.camel_to_snake(value.__name__, '-')
1126
+
1127
+ @staticmethod
1128
+ def max_collapse_level(
1129
+ original_level: int | None,
1130
+ subtree_uncollapse_level: int | None,
1131
+ root_path: KeyPath
1132
+ ) -> int | None:
1133
+ """Consolidates the collapse level."""
1134
+ if original_level is None or subtree_uncollapse_level is None:
1135
+ return None
1136
+ return max(original_level, root_path.depth + subtree_uncollapse_level)
1048
1137
 
1049
1138
 
1050
1139
  _REGEX_CAMEL_TO_SNAKE = re.compile(r'(?<!^)(?=[A-Z])')