pyglove 0.4.5.dev202412100810__py3-none-any.whl → 0.4.5.dev202412130809__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/views/html/controls/label.py +1 -1
- pyglove/core/views/html/controls/label_test.py +6 -6
- pyglove/core/views/html/controls/progress_bar_test.py +2 -2
- pyglove/core/views/html/controls/tab.py +80 -2
- pyglove/core/views/html/controls/tab_test.py +34 -1
- {pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/METADATA +5 -2
- {pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/RECORD +10 -10
- {pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/WHEEL +0 -0
- {pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/top_level.txt +0 -0
@@ -34,7 +34,7 @@ class LabelTest(TestCase):
|
|
34
34
|
label = label_lib.Label('foo')
|
35
35
|
self.assertIsNone(label.tooltip)
|
36
36
|
self.assertIsNone(label.link)
|
37
|
-
self.assert_html_content(label, '<
|
37
|
+
self.assert_html_content(label, '<span class="label">foo</span>')
|
38
38
|
with self.assertRaisesRegex(ValueError, 'Non-interactive .*'):
|
39
39
|
label.update('bar')
|
40
40
|
|
@@ -54,7 +54,7 @@ class LabelTest(TestCase):
|
|
54
54
|
self.assert_html_content(
|
55
55
|
label,
|
56
56
|
(
|
57
|
-
'<div class="label-container"><
|
57
|
+
'<div class="label-container"><span class="label">foo</span>'
|
58
58
|
'<span class="tooltip">bar</span></div>'
|
59
59
|
)
|
60
60
|
)
|
@@ -130,7 +130,7 @@ class LabelTest(TestCase):
|
|
130
130
|
|
131
131
|
def test_badge(self):
|
132
132
|
badge = label_lib.Badge('foo')
|
133
|
-
self.assert_html_content(badge, '<
|
133
|
+
self.assert_html_content(badge, '<span class="label badge">foo</span>')
|
134
134
|
|
135
135
|
|
136
136
|
class LabelGroupTest(TestCase):
|
@@ -140,9 +140,9 @@ class LabelGroupTest(TestCase):
|
|
140
140
|
self.assert_html_content(
|
141
141
|
group,
|
142
142
|
(
|
143
|
-
'<div class="label-group"><
|
144
|
-
'<
|
145
|
-
'<
|
143
|
+
'<div class="label-group"><span class="label group-name">baz</span>'
|
144
|
+
'<span class="label group-value">foo</span>'
|
145
|
+
'<span class="label group-value">bar</span></div>'
|
146
146
|
)
|
147
147
|
)
|
148
148
|
|
@@ -42,8 +42,8 @@ class ProgressBarTest(unittest.TestCase):
|
|
42
42
|
f'<div class="sub-progress foo" id="{bar["foo"].element_id()}">'
|
43
43
|
'</div><div class="sub-progress bar" '
|
44
44
|
f'id="{bar["bar"].element_id()}"></div></div>'
|
45
|
-
'<div class="label-container"><
|
46
|
-
f' id="{bar._progress_label.element_id()}">n/a</
|
45
|
+
'<div class="label-container"><span class="label progress-label"'
|
46
|
+
f' id="{bar._progress_label.element_id()}">n/a</span><span class='
|
47
47
|
f'"tooltip" id="{bar._progress_label.tooltip.element_id()}">'
|
48
48
|
'Not started</span></div></div>'
|
49
49
|
)
|
@@ -13,7 +13,7 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
"""Tab control."""
|
15
15
|
|
16
|
-
from typing import Annotated, List, Literal, Union
|
16
|
+
from typing import Annotated, List, Literal, Optional, Union
|
17
17
|
|
18
18
|
from pyglove.core.symbolic import flags as pg_flags
|
19
19
|
from pyglove.core.symbolic import object as pg_object
|
@@ -44,6 +44,11 @@ class Tab(pg_object.Object):
|
|
44
44
|
'The CSS classes of the tab.'
|
45
45
|
] = []
|
46
46
|
|
47
|
+
name: Annotated[
|
48
|
+
Optional[str],
|
49
|
+
'An optional name that can be used to identify a tab under a tab control'
|
50
|
+
] = None
|
51
|
+
|
47
52
|
|
48
53
|
@pg_object.use_init_args(
|
49
54
|
['tabs', 'selected', 'tab_position', 'id', 'css_classes', 'styles']
|
@@ -87,10 +92,84 @@ class TabControl(HtmlControl):
|
|
87
92
|
position='beforeend',
|
88
93
|
)
|
89
94
|
|
95
|
+
def insert(self, index_or_name: Union[int, str], tab: Tab) -> None:
|
96
|
+
"""Inserts a tab before a tab identified by index or name."""
|
97
|
+
index = self.indexof(index_or_name)
|
98
|
+
if index == -1:
|
99
|
+
raise ValueError(f'Tab not found: {index_or_name!r}')
|
100
|
+
with pg_flags.notify_on_change(False):
|
101
|
+
self.tabs.insert(index, tab)
|
102
|
+
|
103
|
+
self._insert_adjacent_html(
|
104
|
+
f"""
|
105
|
+
const elem = document.querySelectorAll('#{self.element_id()}-button-group > .tab-button')[{index}];
|
106
|
+
""",
|
107
|
+
self._tab_button(tab, len(self.tabs) - 1),
|
108
|
+
position='beforebegin',
|
109
|
+
)
|
110
|
+
self._insert_adjacent_html(
|
111
|
+
f"""
|
112
|
+
const elem = document.querySelectorAll('#{self.element_id()}-content-group > .tab-content')[{index}];
|
113
|
+
""",
|
114
|
+
self._tab_content(tab, len(self.tabs) - 1),
|
115
|
+
position='beforebegin',
|
116
|
+
)
|
117
|
+
|
118
|
+
def indexof(self, index_or_name: Union[int, str]) -> int:
|
119
|
+
if isinstance(index_or_name, int):
|
120
|
+
index = index_or_name
|
121
|
+
if index >= len(self.tabs):
|
122
|
+
return len(self.tabs) - 1
|
123
|
+
elif index < -len(self.tabs):
|
124
|
+
return -1
|
125
|
+
elif index < 0:
|
126
|
+
index = index + len(self.tabs)
|
127
|
+
return index
|
128
|
+
else:
|
129
|
+
name = index_or_name
|
130
|
+
assert isinstance(name, str), name
|
131
|
+
for i, tab in enumerate(self.tabs):
|
132
|
+
if tab.name == name:
|
133
|
+
return i
|
134
|
+
return -1
|
135
|
+
|
90
136
|
def extend(self, tabs: List[Tab]) -> None:
|
91
137
|
for tab in tabs:
|
92
138
|
self.append(tab)
|
93
139
|
|
140
|
+
def select(
|
141
|
+
self,
|
142
|
+
index_or_name: Union[int, str, List[str]]) -> Union[int, str]:
|
143
|
+
"""Selects a tab identified by an index or name.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
index_or_name: The index or name of the tab to select. If a list of names
|
147
|
+
is provided, the first name in the list that is found will be selected.
|
148
|
+
|
149
|
+
Returns:
|
150
|
+
The index (if the index was provided) or name of the selected tab.
|
151
|
+
"""
|
152
|
+
selected_name = index_or_name if isinstance(index_or_name, str) else None
|
153
|
+
index = -1
|
154
|
+
if isinstance(index_or_name, list):
|
155
|
+
for name in index_or_name:
|
156
|
+
index = self.indexof(name)
|
157
|
+
if index != -1:
|
158
|
+
selected_name = name
|
159
|
+
break
|
160
|
+
else:
|
161
|
+
index = self.indexof(index_or_name)
|
162
|
+
if index == -1:
|
163
|
+
raise ValueError(f'Tab not found: {index_or_name!r}')
|
164
|
+
self._sync_members(selected=index)
|
165
|
+
self._run_javascript(
|
166
|
+
f"""
|
167
|
+
const tabButtons = document.querySelectorAll('#{self.element_id()}-button-group > .tab-button');
|
168
|
+
tabButtons[{index}].click();
|
169
|
+
"""
|
170
|
+
)
|
171
|
+
return selected_name or index
|
172
|
+
|
94
173
|
def _to_html(self, **kwargs):
|
95
174
|
return Html.element(
|
96
175
|
'table',
|
@@ -141,7 +220,6 @@ class TabControl(HtmlControl):
|
|
141
220
|
.tab-control {
|
142
221
|
border-spacing: 0px;
|
143
222
|
border-collapse: collapse;
|
144
|
-
height: 100%;
|
145
223
|
margin-top: 10px;
|
146
224
|
}
|
147
225
|
.tab-control td {
|
@@ -36,7 +36,7 @@ class TabControlTest(unittest.TestCase):
|
|
36
36
|
elem_id = tab.element_id()
|
37
37
|
self.assert_html_content(
|
38
38
|
tab,
|
39
|
-
f"""<table class="tab-control"><tr><td><div class="tab-button-group top" id="{elem_id}-button-group"><button class="tab-button selected foo" onclick="openTab(event, '{elem_id}', '{elem_id}-0')"><
|
39
|
+
f"""<table class="tab-control"><tr><td><div class="tab-button-group top" id="{elem_id}-button-group"><button class="tab-button selected foo" onclick="openTab(event, '{elem_id}', '{elem_id}-0')"><span class="label">foo</span></button><button class="tab-button" onclick="openTab(event, '{elem_id}', '{elem_id}-1')"><span class="label">bar</span></button></div></td></tr><tr><td><div class="tab-content-group top" id="{elem_id}-content-group"><div class="tab-content selected foo" id="{elem_id}-0"><h1>foo</h1></div><div class="tab-content" id="{elem_id}-1"><h1>bar</h1></div></div></td></tr></table>"""
|
40
40
|
)
|
41
41
|
with tab.track_scripts() as scripts:
|
42
42
|
tab.extend([
|
@@ -48,6 +48,39 @@ class TabControlTest(unittest.TestCase):
|
|
48
48
|
tab_lib.Tab('qux', base.Html('<h1>qux</h1>')),
|
49
49
|
])
|
50
50
|
self.assertEqual(len(scripts), 6)
|
51
|
+
with tab.track_scripts() as scripts:
|
52
|
+
tab.insert(0, tab_lib.Tab('x', 'foo', name='x'))
|
53
|
+
self.assertEqual(len(scripts), 2)
|
54
|
+
self.assertEqual(len(tab.tabs), 5)
|
55
|
+
self.assertEqual(tab.indexof(-1), 4)
|
56
|
+
self.assertEqual(tab.indexof(3), 3)
|
57
|
+
self.assertEqual(tab.indexof(10), 4)
|
58
|
+
self.assertEqual(tab.indexof(-10), -1)
|
59
|
+
self.assertEqual(tab.indexof('x'), 0)
|
60
|
+
self.assertEqual(tab.indexof('y'), -1)
|
61
|
+
self.assertEqual(tab.select(0), 0)
|
62
|
+
self.assertEqual(tab.select('x'), 'x')
|
63
|
+
self.assertEqual(tab.select(['y', 'x']), 'x')
|
64
|
+
|
65
|
+
with self.assertRaisesRegex(ValueError, 'Tab not found'):
|
66
|
+
tab.select('y')
|
67
|
+
with self.assertRaisesRegex(ValueError, 'Tab not found'):
|
68
|
+
tab.insert('y', tab_lib.Tab('z', 'bar'))
|
69
|
+
|
70
|
+
with tab.track_scripts() as scripts:
|
71
|
+
tab.insert('x', tab_lib.Tab('y', 'bar'))
|
72
|
+
self.assertEqual(len(scripts), 2)
|
73
|
+
self.assertEqual(len(tab.tabs), 6)
|
74
|
+
|
75
|
+
with tab.track_scripts() as scripts:
|
76
|
+
tab.select(3)
|
77
|
+
self.assertEqual(len(scripts), 1)
|
78
|
+
self.assertEqual(tab.selected, 3)
|
79
|
+
|
80
|
+
with tab.track_scripts() as scripts:
|
81
|
+
tab.select('x')
|
82
|
+
self.assertEqual(len(scripts), 1)
|
83
|
+
self.assertEqual(tab.selected, 1)
|
51
84
|
|
52
85
|
|
53
86
|
if __name__ == '__main__':
|
{pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pyglove
|
3
|
-
Version: 0.4.5.
|
3
|
+
Version: 0.4.5.dev202412130809
|
4
4
|
Summary: PyGlove: A library for manipulating Python objects.
|
5
5
|
Home-page: https://github.com/google/pyglove
|
6
6
|
Author: PyGlove Authors
|
@@ -72,7 +72,7 @@ It's commonly used in:
|
|
72
72
|
PyGlove has been [published](https://proceedings.neurips.cc/paper/2020/file/012a91467f210472fab4e11359bbfef6-Paper.pdf)
|
73
73
|
at NeurIPS 2020. It is widely used within [Alphabet](https://abc.xyz/), including Google Research, Google Cloud, Youtube and Waymo.
|
74
74
|
|
75
|
-
PyGlove is developed by Daiyi Peng and colleagues
|
75
|
+
PyGlove is developed by Daiyi Peng and colleagues at [Google Brain](https://research.google/teams/brain/).
|
76
76
|
|
77
77
|
|
78
78
|
## Hello PyGlove
|
@@ -145,6 +145,9 @@ pip install pyglove --pre
|
|
145
145
|
* [Interactive SVG: Components for Direct Manipulation](https://github.com/google/pyglove/blob/main/docs/notebooks/python/interactive_svg.ipynb)
|
146
146
|
* [Where is the Duck: Developing Context-aware Component](https://github.com/google/pyglove/blob/main/docs/notebooks/python/where_is_the_duck.ipynb)
|
147
147
|
|
148
|
+
* Interactive Programming
|
149
|
+
* [Viewing PyGlove objects in HTML](https://colab.research.google.com/github/google/pyglove/blob/main/docs/notebooks/gui/html_view.ipynb)
|
150
|
+
|
148
151
|
## Citing PyGlove
|
149
152
|
|
150
153
|
```
|
@@ -149,12 +149,12 @@ pyglove/core/views/html/tree_view.py,sha256=3Db0aOke-A7Inp-vgqebsDMwJ0Wvaznithkw
|
|
149
149
|
pyglove/core/views/html/tree_view_test.py,sha256=whUorrw0eiDaZsEzGB2B3EN3wx0vLFuNEe2RBU03GeU,74707
|
150
150
|
pyglove/core/views/html/controls/__init__.py,sha256=61qs5pnJPCTECCGBtkbNfIV3KcCu7cxfVNBEtIg1lMo,1318
|
151
151
|
pyglove/core/views/html/controls/base.py,sha256=VV-dDc_myKYlZeiJUXubIJXYKnm1ncEqjlqibN3d4tM,7710
|
152
|
-
pyglove/core/views/html/controls/label.py,sha256=
|
153
|
-
pyglove/core/views/html/controls/label_test.py,sha256=
|
152
|
+
pyglove/core/views/html/controls/label.py,sha256=dXcYId7ASuNqkzKsWMjJ0iQtecoSsUlUgynNNQZOFAM,5681
|
153
|
+
pyglove/core/views/html/controls/label_test.py,sha256=uUYqBSZ0XLOuv4qG20gmoZzA3RxYxpfqT63K0azHEfU,5162
|
154
154
|
pyglove/core/views/html/controls/progress_bar.py,sha256=kLdY3JQLCOv00ShldnQg3Qs8l1j_pDk148FoKfrZB64,5275
|
155
|
-
pyglove/core/views/html/controls/progress_bar_test.py,sha256=
|
156
|
-
pyglove/core/views/html/controls/tab.py,sha256=
|
157
|
-
pyglove/core/views/html/controls/tab_test.py,sha256=
|
155
|
+
pyglove/core/views/html/controls/progress_bar_test.py,sha256=kKOJDZQtBPkmNcgIBrRQkNNzcTm51ojuFBTRUEDSsp0,3506
|
156
|
+
pyglove/core/views/html/controls/tab.py,sha256=ELyroRb3qKQ8ULM_BMq2j-tqV_mnHOvrYv2kbuIe65o,9430
|
157
|
+
pyglove/core/views/html/controls/tab_test.py,sha256=wr1msQjZHxp1TFKQ5LxtppY2Dys736JCmmEJ8WBC3Fo,3531
|
158
158
|
pyglove/core/views/html/controls/tooltip.py,sha256=01BbpuM1twf3FYMUT09_Ck5JSSONe8QE9RmyA9nhCnU,3092
|
159
159
|
pyglove/core/views/html/controls/tooltip_test.py,sha256=17BY-WmZKpz9tCbySPcwG6KJyfeE_MeMyKxtfxorBQ0,3194
|
160
160
|
pyglove/ext/__init__.py,sha256=3jp8cJvKW6PENOZlmVAbT0w-GBRn_kjhc0wDX3XjpOE,755
|
@@ -196,8 +196,8 @@ pyglove/ext/scalars/randoms.py,sha256=LkMIIx7lOq_lvJvVS3BrgWGuWl7Pi91-lA-O8x_gZs
|
|
196
196
|
pyglove/ext/scalars/randoms_test.py,sha256=nEhiqarg8l_5EOucp59CYrpO2uKxS1pe0hmBdZUzRNM,2000
|
197
197
|
pyglove/ext/scalars/step_wise.py,sha256=IDw3tuTpv0KVh7AN44W43zqm1-E0HWPUlytWOQC9w3Y,3789
|
198
198
|
pyglove/ext/scalars/step_wise_test.py,sha256=TL1vJ19xVx2t5HKuyIzGoogF7N3Rm8YhLE6JF7i0iy8,2540
|
199
|
-
pyglove-0.4.5.
|
200
|
-
pyglove-0.4.5.
|
201
|
-
pyglove-0.4.5.
|
202
|
-
pyglove-0.4.5.
|
203
|
-
pyglove-0.4.5.
|
199
|
+
pyglove-0.4.5.dev202412130809.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
200
|
+
pyglove-0.4.5.dev202412130809.dist-info/METADATA,sha256=nDfx3t7PuUS5y9KUG0VnnEaDmtF90a_8a9r16-1Q1m0,6828
|
201
|
+
pyglove-0.4.5.dev202412130809.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
202
|
+
pyglove-0.4.5.dev202412130809.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
|
203
|
+
pyglove-0.4.5.dev202412130809.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{pyglove-0.4.5.dev202412100810.dist-info → pyglove-0.4.5.dev202412130809.dist-info}/top_level.txt
RENAMED
File without changes
|