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.
@@ -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
+