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.
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
  """Symbolic differences."""
15
15
 
16
- from typing import Any, Callable, Optional, Sequence, Tuple, Union
16
+ from typing import Any, Callable, List, Optional, Tuple, Union
17
17
 
18
18
  from pyglove.core import object_utils
19
19
  from pyglove.core import typing as pg_typing
@@ -196,25 +196,26 @@ class Diff(PureSymbolic, pg_object.Object):
196
196
  view: html.HtmlTreeView,
197
197
  parent: Any,
198
198
  root_path: object_utils.KeyPath,
199
- css_class: Optional[Sequence[str]] = None,
200
199
  **kwargs
201
200
  ) -> html.Html:
202
- del parent
203
- user_specified_css_class = css_class or []
204
201
  if not bool(self):
205
202
  if self.value == Diff.MISSING:
206
203
  root = html.Html.element(
207
204
  'span',
208
205
  # CSS class already defined in HtmlTreeView.
209
- css_class=['diff_empty'] + user_specified_css_class,
206
+ css_class=['diff_empty']
210
207
  )
211
208
  else:
212
209
  # When there is no diff, but the same value needs to be displayed
213
210
  # we simply return the value.
214
- root = view.content(
215
- self.value,
216
- css_class=['diff_left', 'diff_right'] + user_specified_css_class,
217
- root_path=root_path, **kwargs
211
+ root = html.Html.element(
212
+ 'div',
213
+ [
214
+ view.content(
215
+ self.value, parent=parent, root_path=root_path, **kwargs,
216
+ )
217
+ ],
218
+ css_class=['diff_left', 'diff_right']
218
219
  )
219
220
  elif self.is_leaf:
220
221
  root = html.Html.element(
@@ -241,7 +242,7 @@ class Diff(PureSymbolic, pg_object.Object):
241
242
  css_class=['diff_right'],
242
243
  ) if self.right != Diff.MISSING else None,
243
244
  ],
244
- css_class=['diff_value'] + user_specified_css_class,
245
+ css_class=['diff_value']
245
246
  )
246
247
  else:
247
248
  assert isinstance(self.left, type)
@@ -279,10 +280,14 @@ class Diff(PureSymbolic, pg_object.Object):
279
280
  ],
280
281
  css_class=[
281
282
  'complex_value', view.css_class_name(self.left)
282
- ] + user_specified_css_class,
283
+ ]
283
284
  )
284
- return root.add_style(
285
+ return root
286
+
287
+ def _html_style(self) -> List[str]:
288
+ return [
285
289
  """
290
+ /* Diff styles. */
286
291
  .diff .summary_title::after {
287
292
  content: ' (diff)';
288
293
  color: #aaa;
@@ -331,7 +336,7 @@ class Diff(PureSymbolic, pg_object.Object):
331
336
  background-color: #ccffcc;
332
337
  }
333
338
  """
334
- )
339
+ ]
335
340
 
336
341
 
337
342
  # NOTE(daiyip): we add the symbolic attribute to Diff after its declaration
@@ -403,6 +403,26 @@ class DiffTest(unittest.TestCase):
403
403
  color: darkred;
404
404
  font-style: italic;
405
405
  }
406
+ /* Value details styles. */
407
+ details.pyglove {
408
+ border: 1px solid #aaa;
409
+ border-radius: 4px;
410
+ padding: 0.5em 0.5em 0;
411
+ margin: 0.1em 0;
412
+ }
413
+ details.pyglove.special_value {
414
+ margin-bottom: 0.75em;
415
+ }
416
+ details.pyglove[open] {
417
+ padding: 0.5em 0.5em 0.5em;
418
+ }
419
+ .highlight {
420
+ background-color: Mark;
421
+ }
422
+ .lowlight {
423
+ opacity: 0.2;
424
+ }
425
+ /* Diff styles. */
406
426
  .diff .summary_title::after {
407
427
  content: ' (diff)';
408
428
  color: #aaa;
@@ -450,25 +470,6 @@ class DiffTest(unittest.TestCase):
450
470
  .diff_value .diff_right > details {
451
471
  background-color: #ccffcc;
452
472
  }
453
- /* Value details styles. */
454
- details.pyglove {
455
- border: 1px solid #aaa;
456
- border-radius: 4px;
457
- padding: 0.5em 0.5em 0;
458
- margin: 0.1em 0;
459
- }
460
- details.pyglove.special_value {
461
- margin-bottom: 0.75em;
462
- }
463
- details.pyglove[open] {
464
- padding: 0.5em 0.5em 0.5em;
465
- }
466
- .highlight {
467
- background-color: Mark;
468
- }
469
- .lowlight {
470
- opacity: 0.2;
471
- }
472
473
  </style>
473
474
  """
474
475
  )
@@ -477,7 +478,7 @@ class DiffTest(unittest.TestCase):
477
478
  assert_content(
478
479
  pg_diff(1, 1).to_html(),
479
480
  """
480
- <details open class="pyglove diff"><summary><div class="summary_title">Diff</div><span class="tooltip">No diff</span></summary><span class="diff_empty"></span></details>
481
+ <details open class="pyglove diff"><summary><div class="summary_title">Diff</div><span class="tooltip diff">No diff</span></summary><span class="diff_empty"></span></details>
481
482
  """
482
483
  )
483
484
 
@@ -485,7 +486,7 @@ class DiffTest(unittest.TestCase):
485
486
  assert_content(
486
487
  pg_diff(1, 1, mode='both').to_html(),
487
488
  """
488
- <span class="simple_value int diff_left diff_right">1</span>
489
+ <div class="diff_left diff_right"><span class="simple_value int">1</span></div>
489
490
  """
490
491
  )
491
492
  # No diff complex value (diff only)
@@ -511,7 +512,7 @@ class DiffTest(unittest.TestCase):
511
512
  enable_key_tooltip=False,
512
513
  ),
513
514
  """
514
- <details open class="pyglove diff"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo diff_left diff_right"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key">0</span></td><td><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">3</span></td></tr></table></div></details></td></tr></table></div></details></td></tr></table></div></details>
515
+ <details open class="pyglove diff"><summary><div class="summary_title">Foo(...)</div></summary><div class="diff_left diff_right"><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int">0</span></td><td><div><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div></td></tr></table></div></div></details>
515
516
  """
516
517
  )
517
518
 
@@ -530,7 +531,7 @@ class DiffTest(unittest.TestCase):
530
531
  enable_key_tooltip=False,
531
532
  ),
532
533
  """
533
- <details open class="pyglove diff"><summary><div class="summary_title">List</div></summary><div class="complex_value list"><table><tr><td><span class="object_key no_diff_key">0</span><span class="tooltip">[0]</span></td><td><span class="simple_value int diff_left diff_right">0</span></td></tr><tr><td><span class="object_key">1</span><span class="tooltip">[1]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">1</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key">2</span><span class="tooltip">[2]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div></div></td></tr></table></div></details>
534
+ <details open class="pyglove diff"><summary><div class="summary_title">List</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int no_diff_key">0</span><span class="tooltip key-path">[0]</span></td><td><div class="diff_left diff_right"><span class="simple_value int">0</span></div></td></tr><tr><td><span class="object_key int">1</span><span class="tooltip key-path">[1]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">1</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key int">2</span><span class="tooltip key-path">[2]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div></div></td></tr></table></div></details>
534
535
  """
535
536
  )
536
537
 
@@ -541,7 +542,7 @@ class DiffTest(unittest.TestCase):
541
542
  enable_key_tooltip=False,
542
543
  ),
543
544
  """
544
- <details open class="pyglove diff"><summary><div class="summary_title">dict</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key no_diff_key">x</span><span class="tooltip">x</span></td><td><span class="simple_value int diff_left diff_right">1</span></td></tr><tr><td><span class="object_key">y</span><span class="tooltip">y</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key">z</span><span class="tooltip">z</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key">w</span><span class="tooltip">w</span></td><td><div class="diff_value"><div class="diff_right"><span class="simple_value int">4</span></div></div></td></tr></table></div></details>
545
+ <details open class="pyglove diff"><summary><div class="summary_title">dict</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key str no_diff_key">x</span><span class="tooltip key-path">x</span></td><td><div class="diff_left diff_right"><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span><span class="tooltip key-path">y</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key str">z</span><span class="tooltip key-path">z</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key str">w</span><span class="tooltip key-path">w</span></td><td><div class="diff_value"><div class="diff_right"><span class="simple_value int">4</span></div></div></td></tr></table></div></details>
545
546
  """
546
547
  )
547
548
 
@@ -556,7 +557,7 @@ class DiffTest(unittest.TestCase):
556
557
  enable_key_tooltip=False,
557
558
  ),
558
559
  """
559
- <details open class="pyglove diff"><summary><div class="summary_title">Foo</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span><span class="tooltip">x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">1</span></div></div></td></tr><tr><td><span class="object_key">y</span><span class="tooltip">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span><span class="tooltip">y.x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key no_diff_key">y</span><span class="tooltip">y.y</span></td><td><span class="simple_value int diff_left diff_right">3</span></td></tr></table></div></details></td></tr></table></div></details>
560
+ <details open class="pyglove diff"><summary><div class="summary_title">Foo</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span><span class="tooltip key-path">x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">1</span></div></div></td></tr><tr><td><span class="object_key str">y</span><span class="tooltip key-path">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span><span class="tooltip key-path">y.x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key str no_diff_key">y</span><span class="tooltip key-path">y.y</span></td><td><div class="diff_left diff_right"><span class="simple_value int">3</span></div></td></tr></table></div></details></td></tr></table></div></details>
560
561
  """
561
562
  )
562
563
 
@@ -571,7 +572,7 @@ class DiffTest(unittest.TestCase):
571
572
  enable_key_tooltip=False,
572
573
  ),
573
574
  """
574
- <div class="diff_value"><div class="diff_left"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">3</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">3</span></td></tr></table></div></details></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove bar"><summary><div class="summary_title">Bar(...)</div></summary><div class="complex_value bar"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">3</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">3</span></td></tr></table></div></details></td></tr></table></div></details></div></div>
575
+ <div class="diff_value"><div class="diff_left"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">3</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove bar"><summary><div class="summary_title">Bar(...)</div></summary><div class="complex_value bar"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">3</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div></div>
575
576
  """
576
577
  )
577
578
 
@@ -586,7 +587,7 @@ class DiffTest(unittest.TestCase):
586
587
  enable_key_tooltip=False,
587
588
  ),
588
589
  """
589
- <details open class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key no_diff_key">x</span><span class="tooltip">x</span></td><td><span class="simple_value int diff_left diff_right">2</span></td></tr><tr><td><span class="object_key">y</span><span class="tooltip">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key no_diff_key">x</span><span class="tooltip">y.x</span></td><td><span class="simple_value int diff_left diff_right">3</span></td></tr><tr><td><span class="object_key no_diff_key">y</span><span class="tooltip">y.y</span></td><td><span class="simple_value int diff_left diff_right">3</span></td></tr></table></div></details></td></tr></table></div></details>
590
+ <details open class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str no_diff_key">x</span><span class="tooltip key-path">x</span></td><td><div class="diff_left diff_right"><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span><span class="tooltip key-path">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str no_diff_key">x</span><span class="tooltip key-path">y.x</span></td><td><div class="diff_left diff_right"><span class="simple_value int">3</span></div></td></tr><tr><td><span class="object_key str no_diff_key">y</span><span class="tooltip key-path">y.y</span></td><td><div class="diff_left diff_right"><span class="simple_value int">3</span></div></td></tr></table></div></details></td></tr></table></div></details>
590
591
  """
591
592
  )
592
593
 
@@ -601,7 +602,7 @@ class DiffTest(unittest.TestCase):
601
602
  enable_key_tooltip=False,
602
603
  ),
603
604
  """
604
- <details open class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span><span class="tooltip">x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key">y</span><span class="tooltip">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span><span class="tooltip">y.x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key no_diff_key">y</span><span class="tooltip">y.y</span></td><td><span class="simple_value int diff_left diff_right">3</span></td></tr></table></div></details></td></tr></table></div></details>
605
+ <details open class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span><span class="tooltip key-path">x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">2</span></div><div class="diff_right"><span class="simple_value int">3</span></div></div></td></tr><tr><td><span class="object_key str">y</span><span class="tooltip key-path">y</span></td><td><details class="pyglove diff"><summary><div class="summary_title">Foo | Bar</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span><span class="tooltip key-path">y.x</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value int">3</span></div><div class="diff_right"><span class="simple_value int">2</span></div></div></td></tr><tr><td><span class="object_key str no_diff_key">y</span><span class="tooltip key-path">y.y</span></td><td><div class="diff_left diff_right"><span class="simple_value int">3</span></div></td></tr></table></div></details></td></tr></table></div></details>
605
606
  """
606
607
  )
607
608
 
@@ -623,7 +624,7 @@ class DiffTest(unittest.TestCase):
623
624
  uncollapse=['[0]', '[1].right', '[3].left.y'],
624
625
  ),
625
626
  """
626
- <details open class="pyglove diff"><summary><div class="summary_title">List</div></summary><div class="complex_value list"><table><tr><td><span class="object_key no_diff_key">0</span><span class="tooltip">[0]</span></td><td><details open class="pyglove diff"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo diff_left diff_right"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">2</span></td></tr></table></div></details></td></tr><tr><td><span class="object_key">1</span><span class="tooltip">[1]</span></td><td><div class="diff_value"><div class="diff_left"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">2</span></td></tr></table></div></details></div><div class="diff_right"><details open class="pyglove bar"><summary><div class="summary_title">Bar(...)</div></summary><div class="complex_value bar"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">2</span></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key">2</span><span class="tooltip">[2]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value none-type">None</span></div><div class="diff_right"><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key">3</span><span class="tooltip">[3]</span></td><td><div class="diff_value"><div class="diff_left"><details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">3</span></td></tr></table></div></details></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key">0</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">1</span></td><td><span class="simple_value int">2</span></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key">4</span><span class="tooltip">[4]</span></td><td><div class="diff_value"><div class="diff_left"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key">0</span></td><td><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">2</span></td></tr></table></div></details></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">2</span></td></tr><tr><td><span class="object_key">y</span></td><td><span class="simple_value int">4</span></td></tr></table></div></details></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key">5</span><span class="tooltip">[5]</span></td><td><div class="diff_value"><div class="diff_right"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key">0</span></td><td><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">3</span></td></tr></table></div></details></td></tr></table></div></details></div></div></td></tr></table></div></details>
627
+ <details open class="pyglove diff"><summary><div class="summary_title">List</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int no_diff_key">0</span><span class="tooltip key-path">[0]</span></td><td><details open class="pyglove diff"><summary><div class="summary_title">Foo(...)</div></summary><div class="diff_left diff_right"><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">2</span></div></td></tr></table></div></div></details></td></tr><tr><td><span class="object_key int">1</span><span class="tooltip key-path">[1]</span></td><td><div class="diff_value"><div class="diff_left"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">2</span></div></td></tr></table></div></details></div><div class="diff_right"><details open class="pyglove bar"><summary><div class="summary_title">Bar(...)</div></summary><div class="complex_value bar"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">2</span></div></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key int">2</span><span class="tooltip key-path">[2]</span></td><td><div class="diff_value"><div class="diff_left"><span class="simple_value none-type">None</span></div><div class="diff_right"><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key int">3</span><span class="tooltip key-path">[3]</span></td><td><div class="diff_value"><div class="diff_left"><details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int">0</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key int">1</span></td><td><div><span class="simple_value int">2</span></div></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key int">4</span><span class="tooltip key-path">[4]</span></td><td><div class="diff_value"><div class="diff_left"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int">0</span></td><td><div><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">2</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div><div class="diff_right"><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><details class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">2</span></div></td></tr><tr><td><span class="object_key str">y</span></td><td><div><span class="simple_value int">4</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div></div></td></tr><tr><td><span class="object_key int">5</span><span class="tooltip key-path">[5]</span></td><td><div class="diff_value"><div class="diff_right"><details class="pyglove list"><summary><div class="summary_title">List(...)</div></summary><div class="complex_value list"><table><tr><td><span class="object_key int">0</span></td><td><div><details class="pyglove dict"><summary><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></td></tr></table></div></details></div></div></td></tr></table></div></details>
627
628
  """
628
629
  )
629
630
 
@@ -14,7 +14,7 @@
14
14
  """Symbolic reference."""
15
15
 
16
16
  import numbers
17
- from typing import Any, Callable, Optional, Tuple
17
+ from typing import Any, Callable, List, Optional, Tuple
18
18
  from pyglove.core import object_utils
19
19
  from pyglove.core import typing as pg_typing
20
20
  from pyglove.core.symbolic import base
@@ -182,14 +182,17 @@ class Ref(Object, base.Inferential):
182
182
  self,
183
183
  title=title or f'{type(self._value).__name__}(...)',
184
184
  **kwargs
185
- ).add_style(
185
+ )
186
+
187
+ def _html_style(self) -> List[str]:
188
+ return [
186
189
  """
187
190
  details.ref .summary_title::before {
188
191
  content: 'ref: ';
189
192
  color: #aaa;
190
193
  }
191
194
  """
192
- )
195
+ ]
193
196
 
194
197
 
195
198
  def maybe_ref(value: Any) -> Optional[Ref]:
@@ -223,26 +223,26 @@ class RefTest(unittest.TestCase):
223
223
  visibility: visible;
224
224
  background-color: darkblue;
225
225
  }
226
- .complex_value .object_key{
226
+ .object_key.str {
227
227
  color: gray;
228
228
  border: 1px solid lightgray;
229
229
  background-color: ButtonFace;
230
230
  border-radius: 0.2em;
231
231
  padding: 0.3em;
232
232
  }
233
- .complex_value.list .object_key{
233
+ .object_key.int::before{
234
+ content: '[';
235
+ }
236
+ .object_key.int::after{
237
+ content: ']';
238
+ }
239
+ .object_key.int{
234
240
  border: 0;
235
241
  color: lightgray;
236
242
  background-color: transparent;
237
243
  border-radius: 0;
238
244
  padding: 0;
239
245
  }
240
- .complex_value.list .object_key::before{
241
- content: '[';
242
- }
243
- .complex_value.list .object_key::after{
244
- content: ']';
245
- }
246
246
  /* Simple value styles. */
247
247
  .simple_value {
248
248
  color: blue;
@@ -294,7 +294,7 @@ class RefTest(unittest.TestCase):
294
294
  enable_key_tooltip=False,
295
295
  ),
296
296
  """
297
- <details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><details class="pyglove ref"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key">x</span></td><td><span class="simple_value int">1</span></td></tr></table></div></details></td></tr></table></div></details>
297
+ <details open class="pyglove foo"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><details class="pyglove ref"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value foo"><table><tr><td><span class="object_key str">x</span></td><td><div><span class="simple_value int">1</span></div></td></tr></table></div></details></div></td></tr></table></div></details>
298
298
  """
299
299
  )
300
300
 
@@ -131,6 +131,7 @@ import copy as copy_lib
131
131
  import functools
132
132
  import inspect
133
133
  import io
134
+ import os
134
135
  import types
135
136
  from typing import Any, Callable, ContextManager, Dict, Iterator, Optional, Sequence, Set, Type, Union
136
137
 
@@ -330,6 +331,7 @@ class Content(object_utils.Formattable, metaclass=abc.ABCMeta):
330
331
 
331
332
  def save(self, file: str, **kwargs):
332
333
  """Save content to a file."""
334
+ pg_io.mkdirs(os.path.dirname(file), exist_ok=True)
333
335
  pg_io.writefile(file, self.to_str(**kwargs))
334
336
 
335
337
  def __add__(self, other: WritableTypes) -> 'Content':
@@ -209,7 +209,7 @@ class ContentTest(unittest.TestCase):
209
209
  self.assertEqual(document.content, 'abcdefghijklmno')
210
210
 
211
211
  def test_save(self):
212
- filename = os.path.join(tempfile.gettempdir(), 'test_doc.txt')
212
+ filename = os.path.join(tempfile.gettempdir(), '1', 'test_doc.txt')
213
213
  Document('abc', ref_links=['https://x/y.css']).save(filename)
214
214
  self.assertTrue(pg_io.path_exists(filename))
215
215
  self.assertEqual(pg_io.readfile(filename), 'link=https://x/y.css\nabc')
@@ -18,12 +18,17 @@ import functools
18
18
  import html as html_lib
19
19
  import inspect
20
20
  import typing
21
- from typing import Any, Callable, Dict, Iterable, List, Optional, Union
21
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Union
22
22
 
23
23
  from pyglove.core import object_utils
24
24
  from pyglove.core import typing as pg_typing
25
25
  from pyglove.core.views import base
26
26
 
27
+ NestableStr = Union[
28
+ str,
29
+ Sequence[Union[str, None, Sequence[Optional[str]]]],
30
+ None,
31
+ ]
27
32
 
28
33
  NodeFilter = base.NodeFilter
29
34
  NodeColor = Callable[
@@ -280,7 +285,7 @@ class Html(base.Content):
280
285
  inner_html: Optional[List[WritableTypes]] = None,
281
286
  *,
282
287
  options: Union[str, Iterable[str], None] = None,
283
- css_class: Union[str, Iterable[str], None] = None,
288
+ css_class: NestableStr = None,
284
289
  style: Union[str, Dict[str, Any], None] = None,
285
290
  **properties
286
291
  ) -> 'Html':
@@ -301,21 +306,12 @@ class Html(base.Content):
301
306
  Returns:
302
307
  The opening tag of an HTML element.
303
308
  """
304
- def ws_join(items: Union[str, Iterable[str], None]) -> Optional[str]:
305
- if isinstance(items, str):
306
- return items
307
- elif isinstance(items, list):
308
- return ' '.join(s for s in items if s is not None)
309
- else:
310
- assert items is None, items
311
- return None
312
-
313
309
  s = cls()
314
310
 
315
311
  # Write the open tag.
316
- css_class = ws_join(css_class)
312
+ css_class = cls.concate(css_class)
313
+ options = cls.concate(options)
317
314
  style = cls.style_str(style)
318
- options = ws_join(options)
319
315
  s.write(
320
316
  f'<{tag}',
321
317
  f' {options}' if options else None,
@@ -353,9 +349,24 @@ class Html(base.Content):
353
349
  s, shared_parts_only=True
354
350
  )
355
351
 
352
+ @classmethod
353
+ def concate(
354
+ cls, nestable_str: NestableStr, separator: str = ' '
355
+ ) -> Optional[str]:
356
+ """Concates the string nodes in a nestable object."""
357
+ if isinstance(nestable_str, str):
358
+ return nestable_str
359
+ elif isinstance(nestable_str, list):
360
+ flattened = [cls.concate(s) for s in nestable_str]
361
+ flattened = [s for s in flattened if s is not None]
362
+ return separator.join(flattened) if flattened else None
363
+ else:
364
+ assert nestable_str is None, nestable_str
365
+ return None
366
+
356
367
  @classmethod
357
368
  def style_str(
358
- cls, style: Union[str, Dict[str, Any], None] = None,
369
+ cls, style: Union[str, Dict[str, Any], None],
359
370
  ) -> Optional[str]:
360
371
  """Gets a string representing an inline CSS style.
361
372
 
@@ -392,6 +403,24 @@ class HtmlView(base.View):
392
403
  class Extension(base.View.Extension):
393
404
  """Base class for HtmlView extensions."""
394
405
 
406
+ def _html_style(self) -> List[str]:
407
+ """Returns additional CSS style to add for this extension.
408
+
409
+ Subclasses can override this method to add additional CSS style to the
410
+ rendered HTML.
411
+ """
412
+ return []
413
+
414
+ def _html_element_class(self) -> List[str]:
415
+ """Returns the CSS classes for the rendered element for this node.
416
+
417
+ Subclasses can override this method to add CSS classes to the
418
+ rendered element of this object.
419
+ """
420
+ return [
421
+ object_utils.camel_to_snake(self.__class__.__name__, '-')
422
+ ]
423
+
395
424
  def to_html(
396
425
  self,
397
426
  *,
@@ -696,6 +696,15 @@ class HtmlTest(TestCase):
696
696
  self.assertEqual(Html.escape(Html('foo"bar')), Html('foo&quot;bar'))
697
697
  self.assertEqual(Html.escape(lambda: 'foo"bar'), 'foo&quot;bar')
698
698
 
699
+ def test_concate(self):
700
+ self.assertIsNone(Html.concate(None))
701
+ self.assertIsNone(Html.concate([None, [None, [None, None]]]))
702
+ self.assertEqual(Html.concate('a'), 'a')
703
+ self.assertEqual(Html.concate(['a']), 'a')
704
+ self.assertEqual(Html.concate(['a', None, 'b']), 'a b')
705
+ self.assertEqual(
706
+ Html.concate(['a', 'b', [None, 'c', [None, 'd']]]), 'a b c d')
707
+
699
708
  def test_element(self):
700
709
  # Empty element.
701
710
  self.assertEqual(Html.element('div').content, '<div></div>')