pyglove 0.4.5.dev202411030808__py3-none-any.whl → 0.4.5.dev202411060809__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.
- pyglove/core/__init__.py +8 -0
- pyglove/core/symbolic/base.py +2 -38
- pyglove/core/symbolic/diff.py +14 -13
- pyglove/core/symbolic/object_test.py +1 -0
- pyglove/core/symbolic/ref.py +7 -7
- pyglove/core/views/__init__.py +1 -0
- pyglove/core/views/base.py +14 -8
- pyglove/core/views/base_test.py +1 -1
- pyglove/core/views/html/__init__.py +1 -1
- pyglove/core/views/html/base.py +53 -79
- pyglove/core/views/html/base_test.py +17 -4
- pyglove/core/views/html/controls/__init__.py +35 -0
- pyglove/core/views/html/controls/base.py +238 -0
- pyglove/core/views/html/controls/label.py +190 -0
- pyglove/core/views/html/controls/label_test.py +138 -0
- pyglove/core/views/html/controls/progress_bar.py +185 -0
- pyglove/core/views/html/controls/progress_bar_test.py +97 -0
- pyglove/core/views/html/controls/tab.py +169 -0
- pyglove/core/views/html/controls/tab_test.py +54 -0
- pyglove/core/views/html/controls/tooltip.py +99 -0
- pyglove/core/views/html/controls/tooltip_test.py +99 -0
- pyglove/core/views/html/tree_view.py +24 -6
- pyglove/core/views/html/tree_view_test.py +7 -2
- {pyglove-0.4.5.dev202411030808.dist-info → pyglove-0.4.5.dev202411060809.dist-info}/METADATA +1 -1
- {pyglove-0.4.5.dev202411030808.dist-info → pyglove-0.4.5.dev202411060809.dist-info}/RECORD +28 -18
- {pyglove-0.4.5.dev202411030808.dist-info → pyglove-0.4.5.dev202411060809.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev202411030808.dist-info → pyglove-0.4.5.dev202411060809.dist-info}/WHEEL +0 -0
- {pyglove-0.4.5.dev202411030808.dist-info → pyglove-0.4.5.dev202411060809.dist-info}/top_level.txt +0 -0
pyglove/core/__init__.py
CHANGED
@@ -309,6 +309,14 @@ Html = views.Html
|
|
309
309
|
to_html = views.to_html
|
310
310
|
to_html_str = views.to_html_str
|
311
311
|
|
312
|
+
# NOTE(daiyip): Hack to add `controls` to `pg.views.html`.
|
313
|
+
# We exclude `html.controls` from `pyglove.core.views.html` package to avoid
|
314
|
+
# circular dependency between `pyglove.core.views.html` and
|
315
|
+
# `pyglove.core.symbolic`.
|
316
|
+
from pyglove.core.views.html import controls
|
317
|
+
views.html.controls = controls
|
318
|
+
|
319
|
+
|
312
320
|
#
|
313
321
|
# Symbols from `io` sub-module.
|
314
322
|
#
|
pyglove/core/symbolic/base.py
CHANGED
@@ -31,7 +31,7 @@ from pyglove.core.symbolic import flags
|
|
31
31
|
from pyglove.core.symbolic.origin import Origin
|
32
32
|
from pyglove.core.symbolic.pure_symbolic import NonDeterministic
|
33
33
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
34
|
-
from pyglove.core.views import
|
34
|
+
from pyglove.core.views.html.base import HtmlConvertible
|
35
35
|
|
36
36
|
|
37
37
|
class WritePermissionError(Exception):
|
@@ -175,7 +175,7 @@ class Symbolic(
|
|
175
175
|
object_utils.Formattable,
|
176
176
|
object_utils.JSONConvertible,
|
177
177
|
object_utils.MaybePartial,
|
178
|
-
|
178
|
+
HtmlConvertible,
|
179
179
|
):
|
180
180
|
"""Base for all symbolic types.
|
181
181
|
|
@@ -949,42 +949,6 @@ class Symbolic(
|
|
949
949
|
"""Serializes current object into a JSON string."""
|
950
950
|
return to_json_str(self, json_indent=json_indent, **kwargs)
|
951
951
|
|
952
|
-
def _html_tree_view_content(
|
953
|
-
self,
|
954
|
-
*,
|
955
|
-
view: html.HtmlTreeView,
|
956
|
-
name: Optional[str] = None,
|
957
|
-
parent: Any = None,
|
958
|
-
root_path: Optional[object_utils.KeyPath] = None,
|
959
|
-
extra_flags: Optional[Dict[str, Any]],
|
960
|
-
**kwargs,
|
961
|
-
) -> html.Html:
|
962
|
-
"""Returns the content HTML for a symbolic object.."""
|
963
|
-
extra_flags = extra_flags or {}
|
964
|
-
hide_frozen = extra_flags.get('hide_frozen', True)
|
965
|
-
hide_default_values = extra_flags.get('hide_default_values', False)
|
966
|
-
use_inferred = extra_flags.get('use_inferred', False)
|
967
|
-
|
968
|
-
kv = {}
|
969
|
-
for k, v in self.sym_items():
|
970
|
-
# Apply frozen filter.
|
971
|
-
field = self.sym_attr_field(k)
|
972
|
-
if hide_frozen and field and field.frozen:
|
973
|
-
continue
|
974
|
-
|
975
|
-
# Apply inferred value.
|
976
|
-
if use_inferred and isinstance(v, Inferential):
|
977
|
-
v = self.sym_inferred(k, default=v)
|
978
|
-
|
979
|
-
# Apply default value filter.
|
980
|
-
if field and hide_default_values and eq(v, field.default_value):
|
981
|
-
continue
|
982
|
-
kv[k] = v
|
983
|
-
return view.complex_value(
|
984
|
-
kv, name=name, parent=self, root_path=root_path,
|
985
|
-
extra_flags=extra_flags, **kwargs
|
986
|
-
)
|
987
|
-
|
988
952
|
@classmethod
|
989
953
|
def load(cls, *args, **kwargs) -> Any:
|
990
954
|
"""Loads an instance of this type using the global load handler."""
|
pyglove/core/symbolic/diff.py
CHANGED
@@ -21,10 +21,10 @@ from pyglove.core.symbolic import base
|
|
21
21
|
from pyglove.core.symbolic import list as pg_list
|
22
22
|
from pyglove.core.symbolic import object as pg_object
|
23
23
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
24
|
-
from pyglove.core.views import
|
24
|
+
from pyglove.core.views.html import tree_view
|
25
25
|
|
26
26
|
|
27
|
-
class Diff(PureSymbolic, pg_object.Object):
|
27
|
+
class Diff(PureSymbolic, pg_object.Object, tree_view.HtmlTreeView.Extension):
|
28
28
|
"""A value diff between two objects: a 'left' object and a 'right' object.
|
29
29
|
|
30
30
|
If one of them is missing, it may be represented by pg.Diff.MISSING
|
@@ -149,12 +149,12 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
149
149
|
def _html_tree_view_summary(
|
150
150
|
self,
|
151
151
|
*,
|
152
|
-
view:
|
152
|
+
view: tree_view.HtmlTreeView,
|
153
153
|
css_classes: Optional[Sequence[str]] = None,
|
154
154
|
title: Optional[str] = None,
|
155
155
|
max_summary_len_for_str: int = 80,
|
156
156
|
**kwargs,
|
157
|
-
) -> Optional[
|
157
|
+
) -> Optional[tree_view.Html]:
|
158
158
|
# pytype: enable=annotation-type-mismatch
|
159
159
|
if not bool(self):
|
160
160
|
v = self.value
|
@@ -197,15 +197,16 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
197
197
|
def _html_tree_view_content(
|
198
198
|
self,
|
199
199
|
*,
|
200
|
-
view:
|
201
|
-
parent: Any,
|
202
|
-
root_path: object_utils.KeyPath,
|
200
|
+
view: tree_view.HtmlTreeView,
|
201
|
+
parent: Any = None,
|
202
|
+
root_path: Optional[object_utils.KeyPath] = None,
|
203
203
|
css_classes: Optional[Sequence[str]] = None,
|
204
204
|
**kwargs
|
205
|
-
) ->
|
205
|
+
) -> tree_view.Html:
|
206
|
+
root_path = root_path or object_utils.KeyPath()
|
206
207
|
if not bool(self):
|
207
208
|
if self.value == Diff.MISSING:
|
208
|
-
root =
|
209
|
+
root = tree_view.Html.element(
|
209
210
|
'span',
|
210
211
|
# CSS class already defined in HtmlTreeView.
|
211
212
|
css_classes=['diff-empty']
|
@@ -219,7 +220,7 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
219
220
|
**kwargs,
|
220
221
|
)
|
221
222
|
elif self.is_leaf:
|
222
|
-
root =
|
223
|
+
root = tree_view.Html.element(
|
223
224
|
'div',
|
224
225
|
[
|
225
226
|
view.render( # pylint: disable=g-long-ternary
|
@@ -242,7 +243,7 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
242
243
|
else:
|
243
244
|
key_fn = lambda k: k
|
244
245
|
|
245
|
-
s =
|
246
|
+
s = tree_view.Html()
|
246
247
|
for k, v in self.children.items():
|
247
248
|
k = key_fn(k)
|
248
249
|
child_path = root_path + k
|
@@ -263,7 +264,7 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
263
264
|
),
|
264
265
|
'</td></tr>'
|
265
266
|
)
|
266
|
-
root =
|
267
|
+
root = tree_view.Html.element(
|
267
268
|
'div',
|
268
269
|
[
|
269
270
|
'<table>', s, '</table>'
|
@@ -275,7 +276,7 @@ class Diff(PureSymbolic, pg_object.Object):
|
|
275
276
|
return root
|
276
277
|
|
277
278
|
def _html_tree_view_config(self) -> dict[str, Any]:
|
278
|
-
return
|
279
|
+
return tree_view.HtmlTreeView.get_kwargs(
|
279
280
|
super()._html_tree_view_config(),
|
280
281
|
dict(
|
281
282
|
css_classes=[
|
@@ -39,6 +39,7 @@ from pyglove.core.symbolic.object import use_init_args as pg_use_init_args
|
|
39
39
|
from pyglove.core.symbolic.origin import Origin
|
40
40
|
from pyglove.core.symbolic.pure_symbolic import NonDeterministic
|
41
41
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
42
|
+
from pyglove.core.views.html import tree_view # pylint: disable=unused-import
|
42
43
|
|
43
44
|
|
44
45
|
MISSING_VALUE = object_utils.MISSING_VALUE
|
pyglove/core/symbolic/ref.py
CHANGED
@@ -20,10 +20,10 @@ from pyglove.core import object_utils
|
|
20
20
|
from pyglove.core import typing as pg_typing
|
21
21
|
from pyglove.core.symbolic import base
|
22
22
|
from pyglove.core.symbolic.object import Object
|
23
|
-
from pyglove.core.views import
|
23
|
+
from pyglove.core.views.html import tree_view
|
24
24
|
|
25
25
|
|
26
|
-
class Ref(Object, base.Inferential):
|
26
|
+
class Ref(Object, base.Inferential, tree_view.HtmlTreeView.Extension):
|
27
27
|
"""Symbolic reference.
|
28
28
|
|
29
29
|
When adding a symbolic node to a symbolic tree, it undergoes a copy operation
|
@@ -167,17 +167,17 @@ class Ref(Object, base.Inferential):
|
|
167
167
|
def _html_tree_view_content(
|
168
168
|
self,
|
169
169
|
*,
|
170
|
-
view:
|
171
|
-
**kwargs: Any) ->
|
170
|
+
view: tree_view.HtmlTreeView,
|
171
|
+
**kwargs: Any) -> tree_view.Html:
|
172
172
|
"""Overrides `_html_content` to render the referenced value."""
|
173
173
|
return view.content(self._value, **kwargs)
|
174
174
|
|
175
175
|
def _html_tree_view_summary(
|
176
176
|
self,
|
177
177
|
*,
|
178
|
-
view:
|
178
|
+
view: tree_view.HtmlTreeView,
|
179
179
|
title: Optional[str] = None,
|
180
|
-
**kwargs: Any) -> Optional[
|
180
|
+
**kwargs: Any) -> Optional[tree_view.Html]:
|
181
181
|
"""Overrides `_html_content` to render the referenced value."""
|
182
182
|
return view.summary(
|
183
183
|
self,
|
@@ -188,7 +188,7 @@ class Ref(Object, base.Inferential):
|
|
188
188
|
@classmethod
|
189
189
|
@functools.cache
|
190
190
|
def _html_tree_view_config(cls) -> dict[str, Any]:
|
191
|
-
return
|
191
|
+
return tree_view.HtmlTreeView.get_kwargs(
|
192
192
|
super()._html_tree_view_config(),
|
193
193
|
dict(
|
194
194
|
css_classes=['ref'],
|
pyglove/core/views/__init__.py
CHANGED
pyglove/core/views/base.py
CHANGED
@@ -272,11 +272,10 @@ class Content(object_utils.Formattable, metaclass=abc.ABCMeta):
|
|
272
272
|
self._shared_parts = shared_parts
|
273
273
|
|
274
274
|
for c in content:
|
275
|
+
c = self._to_content(c)
|
275
276
|
if c is None:
|
276
277
|
continue
|
277
|
-
|
278
|
-
c = c()
|
279
|
-
if isinstance(c, str):
|
278
|
+
elif isinstance(c, str):
|
280
279
|
self._content_stream.write(c)
|
281
280
|
else:
|
282
281
|
self.write(c)
|
@@ -306,9 +305,7 @@ class Content(object_utils.Formattable, metaclass=abc.ABCMeta):
|
|
306
305
|
"""
|
307
306
|
content_updated = False
|
308
307
|
for p in parts:
|
309
|
-
|
310
|
-
p = p()
|
311
|
-
|
308
|
+
p = self._to_content(p)
|
312
309
|
if p is None:
|
313
310
|
continue
|
314
311
|
|
@@ -342,8 +339,7 @@ class Content(object_utils.Formattable, metaclass=abc.ABCMeta):
|
|
342
339
|
|
343
340
|
def __add__(self, other: WritableTypes) -> 'Content':
|
344
341
|
"""Operator +: Concatenates two Content objects."""
|
345
|
-
|
346
|
-
other = other()
|
342
|
+
other = self._to_content(other)
|
347
343
|
if not other:
|
348
344
|
return self
|
349
345
|
s = copy_lib.deepcopy(self)
|
@@ -416,6 +412,16 @@ class Content(object_utils.Formattable, metaclass=abc.ABCMeta):
|
|
416
412
|
return value
|
417
413
|
return cls(value) # pytype: disable=not-instantiable
|
418
414
|
|
415
|
+
@classmethod
|
416
|
+
def _to_content(cls, value: WritableTypes) -> Union['Content', str, None]:
|
417
|
+
"""Returns a Content object or None from a writable type."""
|
418
|
+
if callable(value):
|
419
|
+
value = value()
|
420
|
+
if value is None:
|
421
|
+
return None
|
422
|
+
assert isinstance(value, (str, cls)), value
|
423
|
+
return value
|
424
|
+
|
419
425
|
|
420
426
|
def view(
|
421
427
|
value: Any,
|
pyglove/core/views/base_test.py
CHANGED
@@ -17,10 +17,10 @@
|
|
17
17
|
# pylint: disable=g-bad-import-order
|
18
18
|
|
19
19
|
from pyglove.core.views.html.base import Html
|
20
|
+
from pyglove.core.views.html.base import HtmlConvertible
|
20
21
|
from pyglove.core.views.html.base import HtmlView
|
21
22
|
from pyglove.core.views.html.base import to_html
|
22
23
|
from pyglove.core.views.html.base import to_html_str
|
23
|
-
|
24
24
|
from pyglove.core.views.html.tree_view import HtmlTreeView
|
25
25
|
|
26
26
|
# pylint: enable=g-bad-import-order
|
pyglove/core/views/html/base.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2024 The
|
1
|
+
# Copyright 2024 The PyGlove Authors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -86,7 +86,8 @@ class Html(base.Content):
|
|
86
86
|
WritableTypes = Union[ # pylint: disable=invalid-name
|
87
87
|
str,
|
88
88
|
'Html',
|
89
|
-
|
89
|
+
'HtmlConvertible',
|
90
|
+
Callable[[], Union[str, 'Html', 'HtmlConvertible', None]],
|
90
91
|
None
|
91
92
|
]
|
92
93
|
|
@@ -274,6 +275,20 @@ class Html(base.Content):
|
|
274
275
|
Html, super().from_value(value, copy=copy)
|
275
276
|
)
|
276
277
|
|
278
|
+
@classmethod
|
279
|
+
def _to_content(
|
280
|
+
cls, value: WritableTypes
|
281
|
+
) -> Union['Html', str, None]:
|
282
|
+
if callable(value):
|
283
|
+
value = value()
|
284
|
+
if value is None:
|
285
|
+
return None
|
286
|
+
elif isinstance(value, HtmlConvertible):
|
287
|
+
value = value.to_html()
|
288
|
+
elif not isinstance(value, (str, cls)):
|
289
|
+
raise TypeError(f'Not a writable value for `{cls.__name__}`: {value!r}')
|
290
|
+
return value
|
291
|
+
|
277
292
|
#
|
278
293
|
# Helper methods for creating templated Html objects.
|
279
294
|
#
|
@@ -337,13 +352,15 @@ class Html(base.Content):
|
|
337
352
|
cls,
|
338
353
|
s: WritableTypes,
|
339
354
|
javascript_str: bool = False
|
340
|
-
) ->
|
355
|
+
) -> Union[str, 'Html', None]:
|
341
356
|
"""Escapes an HTML writable object."""
|
342
357
|
if s is None:
|
343
358
|
return None
|
344
359
|
|
345
360
|
if callable(s):
|
346
361
|
s = s()
|
362
|
+
if isinstance(s, HtmlConvertible):
|
363
|
+
s = s.to_html()
|
347
364
|
|
348
365
|
def _escape(s: str) -> str:
|
349
366
|
if javascript_str:
|
@@ -413,87 +430,27 @@ class Html(base.Content):
|
|
413
430
|
pg_typing.register_converter(str, Html, convert_fn=Html.from_value)
|
414
431
|
|
415
432
|
|
416
|
-
class
|
417
|
-
"""Base class for HTML
|
433
|
+
class HtmlConvertible:
|
434
|
+
"""Base class for HTML convertible objects."""
|
418
435
|
|
419
|
-
|
420
|
-
"""
|
436
|
+
def to_html(self, **kwargs) -> Html:
|
437
|
+
"""Returns the HTML representation of the object."""
|
438
|
+
return to_html(self, **kwargs)
|
421
439
|
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
Subclasses can override this method to add additional CSS style to the
|
426
|
-
rendered HTML.
|
427
|
-
"""
|
428
|
-
return []
|
429
|
-
|
430
|
-
def _html_element_class(self) -> List[str]:
|
431
|
-
"""Returns the CSS classes for the rendered element for this node.
|
432
|
-
|
433
|
-
Subclasses can override this method to add CSS classes to the
|
434
|
-
rendered element of this object.
|
435
|
-
"""
|
436
|
-
return [
|
437
|
-
object_utils.camel_to_snake(self.__class__.__name__, '-')
|
438
|
-
]
|
439
|
-
|
440
|
-
def to_html(
|
441
|
-
self,
|
442
|
-
*,
|
443
|
-
name: Optional[str] = None,
|
444
|
-
root_path: Optional[object_utils.KeyPath] = None,
|
445
|
-
view_id: str = 'html-tree-view',
|
446
|
-
**kwargs
|
447
|
-
) -> Html:
|
448
|
-
"""Returns the HTML representation of the object.
|
449
|
-
|
450
|
-
Args:
|
451
|
-
name: The name of the object.
|
452
|
-
root_path: The root path of the object.
|
453
|
-
view_id: The ID of the view to render the value.
|
454
|
-
See `pg.views.HtmlView.dir()` for all available HTML view IDs.
|
455
|
-
**kwargs: View-specific keyword arguments passed to `pg.to_html`, wich
|
456
|
-
will be used to construct/override `HtmlView` settings.
|
457
|
-
|
458
|
-
Returns:
|
459
|
-
An rendered HTML.
|
460
|
-
"""
|
461
|
-
return to_html(
|
462
|
-
self, name=name, root_path=root_path, view_id=view_id, **kwargs
|
463
|
-
)
|
440
|
+
def to_html_str(self, *, content_only: bool = False, **kwargs) -> str:
|
441
|
+
"""Returns the HTML str of the object."""
|
442
|
+
return self.to_html(**kwargs).to_str(content_only=content_only)
|
464
443
|
|
465
|
-
|
466
|
-
|
467
|
-
*,
|
468
|
-
name: Optional[str] = None,
|
469
|
-
root_path: Optional[object_utils.KeyPath] = None,
|
470
|
-
view_id: str = 'html-tree-view',
|
471
|
-
content_only: bool = False,
|
472
|
-
**kwargs
|
473
|
-
) -> str:
|
474
|
-
"""Returns the HTML str of the object.
|
475
|
-
|
476
|
-
Args:
|
477
|
-
name: The name of the object.
|
478
|
-
root_path: The root path of the object.
|
479
|
-
view_id: The ID of the view to render the value.
|
480
|
-
See `pg.views.HtmlView.dir()` for all available HTML view IDs.
|
481
|
-
content_only: If True, only the content will be returned.
|
482
|
-
**kwargs: View-specific keyword arguments passed to `pg.to_html`, wich
|
483
|
-
will be used to construct/override `HtmlView` settings.
|
484
|
-
|
485
|
-
Returns:
|
486
|
-
An rendered HTML str.
|
487
|
-
"""
|
488
|
-
return to_html_str(
|
489
|
-
self, name=name, root_path=root_path,
|
490
|
-
view_id=view_id, content_only=content_only, **kwargs
|
491
|
-
)
|
444
|
+
def _repr_html_(self) -> str:
|
445
|
+
return self.to_html_str()
|
492
446
|
|
493
|
-
def _repr_html_(self) -> str:
|
494
|
-
return self.to_html_str()
|
495
447
|
|
496
|
-
|
448
|
+
class HtmlView(base.View):
|
449
|
+
"""Base class for HTML views."""
|
450
|
+
|
451
|
+
class Extension(base.View.Extension, HtmlConvertible):
|
452
|
+
"""Base class for HtmlView extensions."""
|
453
|
+
|
497
454
|
def render(
|
498
455
|
self,
|
499
456
|
value: Any,
|
@@ -503,6 +460,23 @@ class HtmlView(base.View):
|
|
503
460
|
**kwargs
|
504
461
|
) -> Html:
|
505
462
|
"""Renders the input value into an HTML object."""
|
463
|
+
# For customized HtmlConvertible objects, call their `to_html()` method.
|
464
|
+
if (isinstance(value, HtmlConvertible)
|
465
|
+
and not isinstance(value, self.__class__.Extension)
|
466
|
+
and value.__class__.to_html is not HtmlConvertible.to_html):
|
467
|
+
return value.to_html(name=name, root_path=root_path, **kwargs)
|
468
|
+
return self._render(value, name=name, root_path=root_path, **kwargs)
|
469
|
+
|
470
|
+
@abc.abstractmethod
|
471
|
+
def _render(
|
472
|
+
self,
|
473
|
+
value: Any,
|
474
|
+
*,
|
475
|
+
name: Optional[str] = None,
|
476
|
+
root_path: Optional[object_utils.KeyPath] = None,
|
477
|
+
**kwargs
|
478
|
+
) -> Html:
|
479
|
+
"""View's implementation of HTML rendering."""
|
506
480
|
|
507
481
|
|
508
482
|
def to_html(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2024 The
|
1
|
+
# Copyright 2024 The PyGlove Authors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -422,6 +422,10 @@ class SharedPartTest(TestCase):
|
|
422
422
|
|
423
423
|
class HtmlTest(TestCase):
|
424
424
|
|
425
|
+
class Foo(base.HtmlConvertible):
|
426
|
+
def to_html(self, **kwargs):
|
427
|
+
return base.Html('<h1>foo</h1>')
|
428
|
+
|
425
429
|
def test_content_init(self):
|
426
430
|
html = Html()
|
427
431
|
self.assertEqual(html, Html())
|
@@ -446,6 +450,9 @@ class HtmlTest(TestCase):
|
|
446
450
|
)
|
447
451
|
self.assertEqual(html, Html('abcdefghi'))
|
448
452
|
|
453
|
+
html = Html(HtmlTest.Foo())
|
454
|
+
self.assertEqual(html, Html('<h1>foo</h1>'))
|
455
|
+
|
449
456
|
def test_basics(self):
|
450
457
|
html = Html(
|
451
458
|
'<h1>foo</h1>',
|
@@ -583,7 +590,7 @@ class HtmlTest(TestCase):
|
|
583
590
|
html2.write('<div class="c">bar</div>')
|
584
591
|
html2.write('\n<script>\nconsole.log("bar");\n</script>')
|
585
592
|
|
586
|
-
html1.write(
|
593
|
+
html1.write(HtmlTest.Foo())
|
587
594
|
html1.write('\n<script>\nconsole.log("foo");\n</script>\n')
|
588
595
|
html1.write(html2)
|
589
596
|
|
@@ -603,7 +610,7 @@ class HtmlTest(TestCase):
|
|
603
610
|
</script>
|
604
611
|
</head>
|
605
612
|
<body>
|
606
|
-
<
|
613
|
+
<h1>foo</h1>
|
607
614
|
<script>
|
608
615
|
console.log("foo");
|
609
616
|
</script>
|
@@ -618,7 +625,7 @@ class HtmlTest(TestCase):
|
|
618
625
|
self.assert_html(
|
619
626
|
html1.to_str(content_only=True),
|
620
627
|
"""
|
621
|
-
<
|
628
|
+
<h1>foo</h1>
|
622
629
|
<script>
|
623
630
|
console.log("foo");
|
624
631
|
</script>
|
@@ -641,6 +648,8 @@ class HtmlTest(TestCase):
|
|
641
648
|
html2 = Html.from_value(html, copy=True)
|
642
649
|
self.assertIsNot(html2, html)
|
643
650
|
self.assertEqual(html2, html)
|
651
|
+
html3 = Html.from_value(HtmlTest.Foo())
|
652
|
+
self.assertEqual(html3, Html('<h1>foo</h1>'))
|
644
653
|
|
645
654
|
with self.assertRaises(TypeError):
|
646
655
|
Html.from_value(1)
|
@@ -694,9 +703,13 @@ class HtmlTest(TestCase):
|
|
694
703
|
self.assertEqual(Html.escape('foo'), 'foo')
|
695
704
|
self.assertEqual(Html.escape('foo"bar'), 'foo"bar')
|
696
705
|
self.assertEqual(Html.escape(Html('foo"bar')), Html('foo"bar'))
|
706
|
+
self.assertEqual(Html.escape(HtmlTest.Foo()), Html('<h1>foo</h1>'))
|
697
707
|
self.assertEqual(Html.escape(lambda: 'foo"bar'), 'foo"bar')
|
698
708
|
self.assertEqual(Html.escape('"x=y"', javascript_str=True), '\\"x=y\\"')
|
699
709
|
self.assertEqual(Html.escape('x\n"', javascript_str=True), 'x\\n\\"')
|
710
|
+
self.assertEqual(
|
711
|
+
Html.escape(HtmlTest.Foo(), javascript_str=True), Html('<h1>foo</h1>')
|
712
|
+
)
|
700
713
|
|
701
714
|
def test_concate(self):
|
702
715
|
self.assertIsNone(Html.concate(None))
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright 2024 The PyGlove Authors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""Common HTML controls."""
|
15
|
+
|
16
|
+
# pylint: disable=g-importing-member
|
17
|
+
# pylint: disable=g-bad-import-order
|
18
|
+
|
19
|
+
from pyglove.core.views.html.controls.base import HtmlControl
|
20
|
+
|
21
|
+
|
22
|
+
from pyglove.core.views.html.controls.label import Label
|
23
|
+
from pyglove.core.views.html.controls.label import LabelGroup
|
24
|
+
from pyglove.core.views.html.controls.label import Badge
|
25
|
+
|
26
|
+
from pyglove.core.views.html.controls.tooltip import Tooltip
|
27
|
+
|
28
|
+
from pyglove.core.views.html.controls.tab import Tab
|
29
|
+
from pyglove.core.views.html.controls.tab import TabControl
|
30
|
+
|
31
|
+
from pyglove.core.views.html.controls.progress_bar import ProgressBar
|
32
|
+
from pyglove.core.views.html.controls.progress_bar import SubProgress
|
33
|
+
|
34
|
+
# pylint: enable=g-bad-import-order
|
35
|
+
# pylint: enable=g-importing-member
|