evo-widgets 0.2.0__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.
- evo/widgets/__init__.py +257 -0
- evo/widgets/assets/styles.css +151 -0
- evo/widgets/formatters.py +710 -0
- evo/widgets/html.py +128 -0
- evo/widgets/py.typed +0 -0
- evo/widgets/urls.py +309 -0
- evo_widgets-0.2.0.dist-info/METADATA +189 -0
- evo_widgets-0.2.0.dist-info/RECORD +10 -0
- evo_widgets-0.2.0.dist-info/WHEEL +4 -0
- evo_widgets-0.2.0.dist-info/licenses/LICENSE.md +190 -0
evo/widgets/__init__.py
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
"""Evo SDK Widgets.
|
|
13
|
+
|
|
14
|
+
This package provides HTML rendering and IPython formatters for displaying
|
|
15
|
+
Evo SDK objects in Jupyter notebooks.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
In a Jupyter notebook, load the extension to enable rich HTML rendering:
|
|
19
|
+
|
|
20
|
+
%load_ext evo.widgets
|
|
21
|
+
|
|
22
|
+
After loading, any Evo SDK object will automatically render with styled HTML,
|
|
23
|
+
including Portal and Viewer links.
|
|
24
|
+
|
|
25
|
+
Manual API:
|
|
26
|
+
from evo.widgets import get_viewer_url_for_objects
|
|
27
|
+
|
|
28
|
+
# View multiple objects together
|
|
29
|
+
url = get_viewer_url_for_objects(manager, [pointset, grid])
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
from typing import TYPE_CHECKING
|
|
35
|
+
|
|
36
|
+
from .formatters import (
|
|
37
|
+
format_attributes_collection,
|
|
38
|
+
format_base_object,
|
|
39
|
+
format_block_model,
|
|
40
|
+
format_block_model_attributes,
|
|
41
|
+
format_block_model_version,
|
|
42
|
+
format_report,
|
|
43
|
+
format_report_result,
|
|
44
|
+
format_task_result_list,
|
|
45
|
+
format_task_result_with_target,
|
|
46
|
+
format_variogram,
|
|
47
|
+
)
|
|
48
|
+
from .urls import (
|
|
49
|
+
get_blocksync_base_url,
|
|
50
|
+
get_blocksync_block_model_url,
|
|
51
|
+
get_blocksync_block_model_url_from_environment,
|
|
52
|
+
get_blocksync_report_url,
|
|
53
|
+
get_evo_base_url,
|
|
54
|
+
get_hub_code,
|
|
55
|
+
get_portal_url,
|
|
56
|
+
get_portal_url_for_object,
|
|
57
|
+
get_portal_url_from_reference,
|
|
58
|
+
get_viewer_url,
|
|
59
|
+
get_viewer_url_for_object,
|
|
60
|
+
get_viewer_url_for_objects,
|
|
61
|
+
get_viewer_url_from_reference,
|
|
62
|
+
serialize_object_reference,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if TYPE_CHECKING:
|
|
66
|
+
from IPython.core.interactiveshell import InteractiveShell
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"format_attributes_collection",
|
|
70
|
+
"format_base_object",
|
|
71
|
+
"format_block_model",
|
|
72
|
+
"format_block_model_attributes",
|
|
73
|
+
"format_block_model_version",
|
|
74
|
+
"format_report",
|
|
75
|
+
"format_report_result",
|
|
76
|
+
"format_task_result_list",
|
|
77
|
+
"format_task_result_with_target",
|
|
78
|
+
"format_variogram",
|
|
79
|
+
"get_blocksync_base_url",
|
|
80
|
+
"get_blocksync_block_model_url",
|
|
81
|
+
"get_blocksync_block_model_url_from_environment",
|
|
82
|
+
"get_blocksync_report_url",
|
|
83
|
+
"get_evo_base_url",
|
|
84
|
+
"get_hub_code",
|
|
85
|
+
"get_portal_url",
|
|
86
|
+
"get_portal_url_for_object",
|
|
87
|
+
"get_portal_url_from_reference",
|
|
88
|
+
"get_viewer_url",
|
|
89
|
+
"get_viewer_url_for_object",
|
|
90
|
+
"get_viewer_url_for_objects",
|
|
91
|
+
"get_viewer_url_from_reference",
|
|
92
|
+
"load_ipython_extension",
|
|
93
|
+
"serialize_object_reference",
|
|
94
|
+
"unload_ipython_extension",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _register_formatters(ipython: InteractiveShell) -> None:
|
|
99
|
+
"""Register HTML formatters for Evo SDK types.
|
|
100
|
+
|
|
101
|
+
Uses `for_type_by_name` to avoid hard imports of model classes,
|
|
102
|
+
which keeps the presentation layer decoupled from the data models.
|
|
103
|
+
|
|
104
|
+
:param ipython: The IPython shell instance.
|
|
105
|
+
"""
|
|
106
|
+
html_formatter = ipython.display_formatter.formatters["text/html"]
|
|
107
|
+
|
|
108
|
+
# Register formatter for BaseObject and all subclasses (typed objects like PointSet, TensorGrid)
|
|
109
|
+
# Using for_type_by_name avoids importing the class directly
|
|
110
|
+
html_formatter.for_type_by_name(
|
|
111
|
+
"evo.objects.typed.base",
|
|
112
|
+
"_BaseObject",
|
|
113
|
+
format_base_object,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Register formatter for Variogram (overrides BaseObject for variogram-specific rendering)
|
|
117
|
+
html_formatter.for_type_by_name(
|
|
118
|
+
"evo.objects.typed.variogram",
|
|
119
|
+
"Variogram",
|
|
120
|
+
format_variogram,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Register formatter for Attributes collection
|
|
124
|
+
html_formatter.for_type_by_name(
|
|
125
|
+
"evo.objects.typed.attributes",
|
|
126
|
+
"Attributes",
|
|
127
|
+
format_attributes_collection,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Register formatters for block model types
|
|
131
|
+
html_formatter.for_type_by_name(
|
|
132
|
+
"evo.blockmodels.data",
|
|
133
|
+
"Version",
|
|
134
|
+
format_block_model_version,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
html_formatter.for_type_by_name(
|
|
138
|
+
"evo.blockmodels.typed.report",
|
|
139
|
+
"Report",
|
|
140
|
+
format_report,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
html_formatter.for_type_by_name(
|
|
144
|
+
"evo.blockmodels.typed.report",
|
|
145
|
+
"ReportResult",
|
|
146
|
+
format_report_result,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Register formatters for BlockModel from evo-objects
|
|
150
|
+
html_formatter.for_type_by_name(
|
|
151
|
+
"evo.objects.typed.block_model_ref",
|
|
152
|
+
"BlockModel",
|
|
153
|
+
format_block_model,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
html_formatter.for_type_by_name(
|
|
157
|
+
"evo.objects.typed.attributes",
|
|
158
|
+
"BlockModelAttributes",
|
|
159
|
+
format_block_model_attributes,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Register formatters for compute task results
|
|
163
|
+
|
|
164
|
+
html_formatter.for_type_by_name(
|
|
165
|
+
"evo.compute.tasks.kriging",
|
|
166
|
+
"KrigingResult",
|
|
167
|
+
format_task_result_with_target,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
html_formatter.for_type_by_name(
|
|
171
|
+
"evo.compute.tasks.common.results",
|
|
172
|
+
"TaskResultList",
|
|
173
|
+
format_task_result_list,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _unregister_formatters(ipython: InteractiveShell) -> None:
|
|
178
|
+
"""Unregister HTML formatters for Evo SDK types.
|
|
179
|
+
|
|
180
|
+
:param ipython: The IPython shell instance.
|
|
181
|
+
"""
|
|
182
|
+
html_formatter = ipython.display_formatter.formatters["text/html"]
|
|
183
|
+
|
|
184
|
+
# Remove registered formatters by type name
|
|
185
|
+
# Note: IPython doesn't have a direct "unregister by name" method,
|
|
186
|
+
# so we need to work with the type_printers dict
|
|
187
|
+
try:
|
|
188
|
+
# Try to get the actual types and remove them
|
|
189
|
+
from evo.objects.typed.attributes import Attributes
|
|
190
|
+
from evo.objects.typed.base import _BaseObject
|
|
191
|
+
from evo.objects.typed.variogram import Variogram
|
|
192
|
+
|
|
193
|
+
html_formatter.type_printers.pop(_BaseObject, None)
|
|
194
|
+
html_formatter.type_printers.pop(Variogram, None)
|
|
195
|
+
html_formatter.type_printers.pop(Attributes, None)
|
|
196
|
+
except ImportError:
|
|
197
|
+
# If types can't be imported, try to clean up by string name
|
|
198
|
+
# This is a best-effort cleanup
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def load_ipython_extension(ipython: InteractiveShell) -> None:
|
|
203
|
+
"""Load the Evo presentation IPython extension.
|
|
204
|
+
|
|
205
|
+
This function is called when the user runs `%load_ext evo.widgets`.
|
|
206
|
+
It registers HTML formatters for all Evo SDK types, enabling rich display
|
|
207
|
+
of objects like PointSet, Regular3DGrid, TensorGrid, etc.
|
|
208
|
+
|
|
209
|
+
It also registers the :class:`~evo.notebooks.FeedbackWidget` as the default
|
|
210
|
+
feedback factory so that SDK operations automatically display a progress
|
|
211
|
+
widget in notebooks.
|
|
212
|
+
|
|
213
|
+
:param ipython: The IPython shell instance.
|
|
214
|
+
|
|
215
|
+
Example:
|
|
216
|
+
In a Jupyter notebook::
|
|
217
|
+
|
|
218
|
+
%load_ext evo.widgets
|
|
219
|
+
|
|
220
|
+
# Now typed objects display with rich HTML formatting
|
|
221
|
+
grid = await object_from_reference(manager, grid_url)
|
|
222
|
+
grid # Shows formatted HTML with Portal/Viewer links
|
|
223
|
+
"""
|
|
224
|
+
_register_formatters(ipython)
|
|
225
|
+
_register_feedback_factory()
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def unload_ipython_extension(ipython: InteractiveShell) -> None:
|
|
229
|
+
"""Unload the Evo presentation IPython extension.
|
|
230
|
+
|
|
231
|
+
This function is called when the user runs `%unload_ext evo.widgets`.
|
|
232
|
+
|
|
233
|
+
:param ipython: The IPython shell instance.
|
|
234
|
+
"""
|
|
235
|
+
_unregister_formatters(ipython)
|
|
236
|
+
_unregister_feedback_factory()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _register_feedback_factory() -> None:
|
|
240
|
+
"""Register :class:`~evo.notebooks.FeedbackWidget` as the default feedback factory."""
|
|
241
|
+
try:
|
|
242
|
+
from evo.common.utils import set_feedback_factory
|
|
243
|
+
from evo.notebooks import FeedbackWidget
|
|
244
|
+
|
|
245
|
+
set_feedback_factory(FeedbackWidget)
|
|
246
|
+
except ImportError:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _unregister_feedback_factory() -> None:
|
|
251
|
+
"""Reset the feedback factory to the default."""
|
|
252
|
+
try:
|
|
253
|
+
from evo.common.utils import reset_feedback_factory
|
|
254
|
+
|
|
255
|
+
reset_feedback_factory()
|
|
256
|
+
except ImportError:
|
|
257
|
+
pass
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/* Evo SDK Presentation Styles
|
|
2
|
+
* Shared CSS styles for Jupyter notebook representations across all Evo SDK packages.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.evo {
|
|
6
|
+
border: 1px solid #ccc;
|
|
7
|
+
border-radius: 3px;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
margin: 8px 0;
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
11
|
+
font-size: 13px;
|
|
12
|
+
display: inline-block;
|
|
13
|
+
max-width: 800px;
|
|
14
|
+
background-color: var(--jp-layout-color1, #fff);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.evo .title {
|
|
18
|
+
font-size: 15px;
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
margin-bottom: 12px;
|
|
21
|
+
color: var(--jp-ui-font-color1, #111);
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: baseline;
|
|
24
|
+
gap: 8px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.evo .title-links {
|
|
28
|
+
font-size: 12px;
|
|
29
|
+
font-weight: normal;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.evo .title-links a {
|
|
33
|
+
color: #0066cc !important;
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.evo .title-links a:hover {
|
|
38
|
+
text-decoration: underline;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.evo table {
|
|
42
|
+
border-collapse: collapse;
|
|
43
|
+
width: auto;
|
|
44
|
+
margin-bottom: 8px;
|
|
45
|
+
table-layout: auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.evo td.label {
|
|
49
|
+
padding: 3px 8px 3px 0;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
vertical-align: top;
|
|
53
|
+
color: var(--jp-ui-font-color1, #333);
|
|
54
|
+
text-align: left;
|
|
55
|
+
width: 0.1%;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.evo td.label-vtop {
|
|
59
|
+
padding: 3px 8px 3px 0;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
vertical-align: top;
|
|
63
|
+
color: var(--jp-ui-font-color1, #333);
|
|
64
|
+
text-align: left;
|
|
65
|
+
width: 0.1%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.evo td.value {
|
|
69
|
+
padding: 3px 0;
|
|
70
|
+
color: var(--jp-ui-font-color1, #111);
|
|
71
|
+
text-align: left;
|
|
72
|
+
width: auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.evo table.nested {
|
|
76
|
+
border-collapse: collapse;
|
|
77
|
+
font-size: 12px;
|
|
78
|
+
margin-bottom: 0;
|
|
79
|
+
width: auto;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.evo table.nested th {
|
|
83
|
+
padding: 3px 12px 3px 0;
|
|
84
|
+
text-align: left;
|
|
85
|
+
font-weight: 600;
|
|
86
|
+
color: var(--jp-ui-font-color1, #333);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.evo table.nested th.right {
|
|
90
|
+
text-align: right;
|
|
91
|
+
padding-right: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.evo table.nested td {
|
|
95
|
+
padding: 3px 12px 3px 0;
|
|
96
|
+
color: var(--jp-ui-font-color1, #111);
|
|
97
|
+
text-align: left;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.evo table.nested td.right {
|
|
101
|
+
text-align: right;
|
|
102
|
+
padding-right: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.evo table.nested tr.alt-row {
|
|
106
|
+
background-color: var(--jp-layout-color2, #f5f5f5);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.evo .section {
|
|
110
|
+
margin-top: 8px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.evo .section-heading {
|
|
114
|
+
font-weight: 600;
|
|
115
|
+
margin-bottom: 6px;
|
|
116
|
+
color: var(--jp-ui-font-color1, #333);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.evo .indent {
|
|
120
|
+
margin-left: 16px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Task result specific styles */
|
|
124
|
+
.evo .attr-highlight {
|
|
125
|
+
background: #e3f2fd;
|
|
126
|
+
padding: 2px 8px;
|
|
127
|
+
border-radius: 3px;
|
|
128
|
+
font-family: monospace;
|
|
129
|
+
font-weight: 600;
|
|
130
|
+
color: #1565c0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.evo .message {
|
|
134
|
+
background: #e8f5e9;
|
|
135
|
+
padding: 6px 10px;
|
|
136
|
+
border-radius: 3px;
|
|
137
|
+
color: #2e7d32;
|
|
138
|
+
margin-bottom: 12px;
|
|
139
|
+
font-size: 12px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.evo .success {
|
|
143
|
+
color: #2e7d32;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.evo .subtitle {
|
|
147
|
+
font-size: 12px;
|
|
148
|
+
color: #666;
|
|
149
|
+
margin-bottom: 8px;
|
|
150
|
+
}
|
|
151
|
+
|