aesoptparam 0.3.6__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.
Potentially problematic release.
This version of aesoptparam might be problematic. Click here for more details.
- aesoptparam/__init__.py +13 -0
- aesoptparam/example.py +110 -0
- aesoptparam/parameterized.py +417 -0
- aesoptparam/parameters.py +641 -0
- aesoptparam/serializer.py +94 -0
- aesoptparam/test/dummy_instance.json +30 -0
- aesoptparam/test/dummy_schema.json +752 -0
- aesoptparam/test/test_parameterized.py +574 -0
- aesoptparam/test/test_parameters.py +519 -0
- aesoptparam/test/test_units.py +369 -0
- aesoptparam/test/test_utils.py +147 -0
- aesoptparam/utils/__init__.py +63 -0
- aesoptparam/utils/html_repr.py +533 -0
- aesoptparam/utils/json_utils.py +127 -0
- aesoptparam/utils/unit_library.ini +233 -0
- aesoptparam/utils/units.py +1060 -0
- aesoptparam-0.3.6.dist-info/METADATA +86 -0
- aesoptparam-0.3.6.dist-info/RECORD +21 -0
- aesoptparam-0.3.6.dist-info/WHEEL +5 -0
- aesoptparam-0.3.6.dist-info/licenses/LICENSE +21 -0
- aesoptparam-0.3.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from gc import get_referents
|
|
3
|
+
from types import FunctionType, ModuleType
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import param as pm
|
|
7
|
+
from param.parameterized import truncate
|
|
8
|
+
|
|
9
|
+
from .json_utils import is_valid_json
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
import markdown
|
|
13
|
+
|
|
14
|
+
has_markdown = True
|
|
15
|
+
except ImportError: # pragma: no cover
|
|
16
|
+
has_markdown = False
|
|
17
|
+
|
|
18
|
+
html_repr_settings = {"max_arr_size": 30}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def param_html_repr(
|
|
22
|
+
key, val, parameter, parametrized, vallen=30, max_arr_size=None
|
|
23
|
+
): # pragma: no cover
|
|
24
|
+
"""HTML representation for a single Parameter object and its value"""
|
|
25
|
+
|
|
26
|
+
if hasattr(parameter, "bounds"):
|
|
27
|
+
if parameter.bounds is None:
|
|
28
|
+
range_ = ""
|
|
29
|
+
elif hasattr(parameter, "inclusive_bounds"):
|
|
30
|
+
bl, bu = parameter.bounds
|
|
31
|
+
il, iu = parameter.inclusive_bounds
|
|
32
|
+
|
|
33
|
+
lb = "" if bl is None else (">=" if il else ">") + str(bl)
|
|
34
|
+
ub = "" if bu is None else ("<=" if iu else "<") + str(bu)
|
|
35
|
+
range_ = lb + (", " if lb and bu else "") + ub
|
|
36
|
+
else:
|
|
37
|
+
range_ = repr(parameter.bounds)
|
|
38
|
+
elif hasattr(parameter, "objects") and parameter.objects:
|
|
39
|
+
range_ = ", ".join(list(map(repr, parameter.objects)))
|
|
40
|
+
elif hasattr(parameter, "class_"):
|
|
41
|
+
if isinstance(parameter.class_, tuple):
|
|
42
|
+
range_ = (
|
|
43
|
+
"type=<code>"
|
|
44
|
+
+ " | ".join(kls.__name__ for kls in parameter.class_)
|
|
45
|
+
+ "</code>"
|
|
46
|
+
)
|
|
47
|
+
else:
|
|
48
|
+
range_ = f"type=<code>{parameter.class_.__name__}</code>"
|
|
49
|
+
elif hasattr(parameter, "regex") and parameter.regex is not None:
|
|
50
|
+
range_ = f"regex({parameter.regex})"
|
|
51
|
+
else:
|
|
52
|
+
range_ = ""
|
|
53
|
+
|
|
54
|
+
if parameter.readonly:
|
|
55
|
+
range_ = " ".join(s for s in ["<i>read-only</i>", range_] if s)
|
|
56
|
+
elif parameter.constant:
|
|
57
|
+
range_ = " ".join(s for s in ["<i>constant</i>", range_] if s)
|
|
58
|
+
|
|
59
|
+
if getattr(parameter, "shape", False):
|
|
60
|
+
if len(range_) > 0:
|
|
61
|
+
range_ += "<br>"
|
|
62
|
+
range_ += f"shape=<code>{parameter.shape}</code>"
|
|
63
|
+
if getattr(parameter, "item_type", False):
|
|
64
|
+
if isinstance(parameter.item_type, tuple):
|
|
65
|
+
item_type = " | ".join(kls.__name__ for kls in parameter.item_type)
|
|
66
|
+
else:
|
|
67
|
+
item_type = parameter.item_type.__name__
|
|
68
|
+
if len(range_) > 0:
|
|
69
|
+
range_ += "<br>"
|
|
70
|
+
range_ += f"item_type=<code>{item_type}</code>"
|
|
71
|
+
|
|
72
|
+
units = getattr(parameter, "units", False)
|
|
73
|
+
if units is None:
|
|
74
|
+
units = "-"
|
|
75
|
+
elif isinstance(units, str):
|
|
76
|
+
units = f"<code>{units}</code>"
|
|
77
|
+
else:
|
|
78
|
+
units = ""
|
|
79
|
+
|
|
80
|
+
if isinstance(val, pm.Parameterized) or (
|
|
81
|
+
type(val) is type and issubclass(val, pm.Parameterized)
|
|
82
|
+
):
|
|
83
|
+
# value = val.param._repr_html_(open=False)
|
|
84
|
+
value = parameterized_repr_html(val, open=False)
|
|
85
|
+
elif (
|
|
86
|
+
isinstance(val, list) and len(val) > 0 and isinstance(val[0], pm.Parameterized)
|
|
87
|
+
):
|
|
88
|
+
value = ListOfParameterized_repr_html(
|
|
89
|
+
key, val, parameter.identifier, False, max_arr_size
|
|
90
|
+
)
|
|
91
|
+
elif hasattr(val, "_repr_html_"):
|
|
92
|
+
value = val._repr_html_()
|
|
93
|
+
elif hasattr(parametrized.param[key], "repr_html"):
|
|
94
|
+
val_pp = parametrized._param__private.values.get(key, None)
|
|
95
|
+
value = parametrized.param[key].repr_html(val, val_pp, max_arr_size)
|
|
96
|
+
else:
|
|
97
|
+
value = repr_val(val, max_arr_size)
|
|
98
|
+
|
|
99
|
+
doc = parameter.doc.strip() if parameter.doc else ""
|
|
100
|
+
if doc.startswith("\x1b"):
|
|
101
|
+
doc = ""
|
|
102
|
+
elif "\n\x1b" in doc:
|
|
103
|
+
doc = doc.split("\n\x1b")[0]
|
|
104
|
+
if has_markdown:
|
|
105
|
+
doc = markdown.markdown(doc)
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
f"<tr>"
|
|
109
|
+
f' <td><p style="margin-bottom: 0px;">{key}</p></td>'
|
|
110
|
+
f' <td style="max-width: 300px; text-align:left;">{doc}</td>'
|
|
111
|
+
f' <td style="text-align:left;">{parameter.__class__.__name__}</td>'
|
|
112
|
+
f' <td style="max-width: 300px;">{range_}</td>'
|
|
113
|
+
f' <td style="max-width: 100px;">{units}</td>'
|
|
114
|
+
f' <td style="min-width: 300px; text-align:left;">{value}</td>'
|
|
115
|
+
f"</tr>\n"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def parameterized_repr_html(p, open, title=None, max_arr_size=None): # pragma: no cover
|
|
120
|
+
"""HTML representation for a Parameterized object"""
|
|
121
|
+
# Changed the layout to set value at the end to make display of nested objects better
|
|
122
|
+
# as well as adding documentation column that is markdown rendered
|
|
123
|
+
if isinstance(p, pm.Parameterized):
|
|
124
|
+
if title is None:
|
|
125
|
+
cls = p.__class__
|
|
126
|
+
title = cls.name + "()"
|
|
127
|
+
value_field = "Value"
|
|
128
|
+
else:
|
|
129
|
+
if title is None:
|
|
130
|
+
cls = p
|
|
131
|
+
title = cls.name
|
|
132
|
+
value_field = "Default"
|
|
133
|
+
openstr = " open" if open else ""
|
|
134
|
+
precedence = sorted(
|
|
135
|
+
[
|
|
136
|
+
(0.5 if el.precedence is None else el.precedence, name)
|
|
137
|
+
for name, el in p.param.objects().items()
|
|
138
|
+
]
|
|
139
|
+
)
|
|
140
|
+
contents_list = []
|
|
141
|
+
for _, name in precedence:
|
|
142
|
+
# Skip .name if it is the default name
|
|
143
|
+
if (name == "name") and (
|
|
144
|
+
p.param[name].doc == "\n String identifier for this object."
|
|
145
|
+
):
|
|
146
|
+
continue
|
|
147
|
+
contents_list.append(
|
|
148
|
+
param_html_repr(name, p[name], p.param[name], p, max_arr_size=max_arr_size)
|
|
149
|
+
)
|
|
150
|
+
contents = "".join(contents_list)
|
|
151
|
+
return (
|
|
152
|
+
f"<details {openstr}>\n"
|
|
153
|
+
' <summary style="display:list-item; outline:none;">\n'
|
|
154
|
+
f" <tt>{title}</tt>\n"
|
|
155
|
+
" </summary>\n"
|
|
156
|
+
' <div style="padding-left:10px; padding-bottom:5px;">\n'
|
|
157
|
+
' <table style="max-width:100%;">\n'
|
|
158
|
+
f' <tr><th style="text-align:left;">Name</th><th style="text-align:left;">Documentation</th><th style="text-align:left;">Type</th><th>Range</th><th>Units</th><th style="text-align:left;">{value_field}</th></tr>\n'
|
|
159
|
+
f"{contents}\n"
|
|
160
|
+
" </table>\n </div>\n</details>\n"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def ListOfParameterized_repr_html(
|
|
165
|
+
title, items, identifier, open=True, max_arr_size=None
|
|
166
|
+
): # pragma: no cover
|
|
167
|
+
"""HTML render an ListOfParameterized as a one column table with each element in the list. Each element is identified by an `identifier`."""
|
|
168
|
+
openstr = " open" if open else ""
|
|
169
|
+
contents = "".join(
|
|
170
|
+
[
|
|
171
|
+
"<tr><td>"
|
|
172
|
+
+ parameterized_repr_html(
|
|
173
|
+
val,
|
|
174
|
+
False,
|
|
175
|
+
val.__class__.name + f"({identifier}=<code>{val[identifier]}</code>)",
|
|
176
|
+
max_arr_size=max_arr_size,
|
|
177
|
+
)
|
|
178
|
+
+ "<td></tr>"
|
|
179
|
+
for val in items
|
|
180
|
+
]
|
|
181
|
+
)
|
|
182
|
+
return (
|
|
183
|
+
f"<details {openstr}>\n"
|
|
184
|
+
' <summary style="display:list-item; outline:none;">\n'
|
|
185
|
+
f" <tt>{title}</tt>\n"
|
|
186
|
+
" </summary>\n"
|
|
187
|
+
' <div style="padding-left:10px; padding-bottom:5px;">\n'
|
|
188
|
+
' <table style="max-width:100%;">\n'
|
|
189
|
+
f" <tr><th></th></tr>\n"
|
|
190
|
+
f"{contents}\n"
|
|
191
|
+
" </table>\n </div>\n</details>\n"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def value_ref_default_repr_html(
|
|
196
|
+
parameter, val, val_pp, max_arr_size
|
|
197
|
+
): # pragma: no cover
|
|
198
|
+
"""HTML render of a parameter with reference and/or default states. `val` is the parameter value after full evaluation (as seen by the user). `val_pp` is the value from `._param__private.values` which is the value that is stored."""
|
|
199
|
+
from ..parameters import Function, Reference
|
|
200
|
+
|
|
201
|
+
if val_pp is None and not parameter.default is None:
|
|
202
|
+
val_pp = parameter.default
|
|
203
|
+
if isinstance(val_pp, Reference):
|
|
204
|
+
title, value = ref_html_repr(val, val_pp, max_arr_size)
|
|
205
|
+
elif isinstance(val_pp, Function):
|
|
206
|
+
title = f"<i>$function:</i> {repr_val(val, max_arr_size)}"
|
|
207
|
+
value = f"<i>definition:</i> <code>{val_pp.source_str}</code><br>"
|
|
208
|
+
elif (val_pp is None) and (not val is None):
|
|
209
|
+
if hasattr(parameter, "default_full") and (not parameter.default_full is None):
|
|
210
|
+
title = f"<i>default full:</i> {repr_val(val, max_arr_size)}"
|
|
211
|
+
value = f"<i>full args:</i> {parameter.default_full}"
|
|
212
|
+
elif hasattr(parameter, "default_interp") and (
|
|
213
|
+
not parameter.default_interp is None
|
|
214
|
+
):
|
|
215
|
+
title = f"<i>default interp:</i> {repr_val(val, max_arr_size)}"
|
|
216
|
+
value = f"<i>interp args:</i> {parameter.default_interp}"
|
|
217
|
+
elif hasattr(parameter, "default_ref") and (not parameter.default_ref is None):
|
|
218
|
+
title, value = ref_html_repr(val, parameter.default_ref, max_arr_size)
|
|
219
|
+
else:
|
|
220
|
+
return "None"
|
|
221
|
+
elif isinstance(val, (float, int)):
|
|
222
|
+
return str(val)
|
|
223
|
+
elif isinstance(parameter, pm.String) and isinstance(val, str):
|
|
224
|
+
return repr_val(val, max_arr_size)
|
|
225
|
+
elif (val_pp is None) and (val is None):
|
|
226
|
+
return "None"
|
|
227
|
+
else:
|
|
228
|
+
return repr_val(val, max_arr_size)
|
|
229
|
+
return (
|
|
230
|
+
f"<details>\n"
|
|
231
|
+
' <summary style="display:list-item; outline:none;">\n'
|
|
232
|
+
f" <tt>{title}</tt>\n"
|
|
233
|
+
" </summary>\n"
|
|
234
|
+
' <div style="padding-left:10px; padding-bottom:5px;">\n'
|
|
235
|
+
f"{value}\n"
|
|
236
|
+
"</div>\n</details>\n"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def repr_val(val, max_arr_size):
|
|
241
|
+
if isinstance(val, str):
|
|
242
|
+
return "'" + val + "'"
|
|
243
|
+
elif isinstance(val, (dict, list, np.ndarray)) and is_valid_json(val, True):
|
|
244
|
+
val = json2html(
|
|
245
|
+
is_valid_json(val, True),
|
|
246
|
+
title=f"{truncate(repr(val))}",
|
|
247
|
+
max_arr_size=max_arr_size,
|
|
248
|
+
display_inline=True,
|
|
249
|
+
)
|
|
250
|
+
return str(val)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def ref_html_repr(val, val_pp, max_arr_size):
|
|
254
|
+
title = f"<i>$ref:</i> {repr_val(val, max_arr_size)}"
|
|
255
|
+
value = f"<i>path:</i> <code>{val_pp.path.strip()}</code>"
|
|
256
|
+
return title, value
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class parameterized_repr_html_class:
|
|
260
|
+
|
|
261
|
+
def __init__(self, parameterized_ins, open=True, title=None, max_arr_size=None):
|
|
262
|
+
self.parameterized_ins = parameterized_ins
|
|
263
|
+
self.open = open
|
|
264
|
+
self.title = title
|
|
265
|
+
self.max_arr_size = max_arr_size
|
|
266
|
+
|
|
267
|
+
def _repr_html_(self):
|
|
268
|
+
return parameterized_repr_html(
|
|
269
|
+
self.parameterized_ins, self.open, self.title, self.max_arr_size
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# %% JSON dict render
|
|
274
|
+
def json2html(
|
|
275
|
+
data_in,
|
|
276
|
+
open_default=False,
|
|
277
|
+
fields=None,
|
|
278
|
+
max_arr_size=None,
|
|
279
|
+
title=None,
|
|
280
|
+
display_inline=False,
|
|
281
|
+
):
|
|
282
|
+
# %% Setting/checking default input
|
|
283
|
+
# Ensuring open_fields is a list of list's
|
|
284
|
+
if not (fields is None or isinstance(fields, bool)):
|
|
285
|
+
if not isinstance(fields, list):
|
|
286
|
+
raise ValueError(f"`fields` has to be a list (given: {fields})")
|
|
287
|
+
if not isinstance(fields[0], list):
|
|
288
|
+
fields = [fields]
|
|
289
|
+
# If root object should be open
|
|
290
|
+
open = open_default
|
|
291
|
+
if isinstance(fields, bool):
|
|
292
|
+
open = fields
|
|
293
|
+
fields = None
|
|
294
|
+
elif fields is not None:
|
|
295
|
+
open = True
|
|
296
|
+
openstr = " open" if open else ""
|
|
297
|
+
# Setting max_arr_size
|
|
298
|
+
if max_arr_size is None:
|
|
299
|
+
data_size = get_data_size(data_in)
|
|
300
|
+
if data_size > 1_000_000: # Rough size of 1000 size 100 arrays
|
|
301
|
+
max_arr_size = 5
|
|
302
|
+
elif data_size > 100_000: # Rough size of 100 size 100 arrays
|
|
303
|
+
max_arr_size = 10
|
|
304
|
+
elif data_size > 10_000: # Rough size of 10 size 100 arrays
|
|
305
|
+
max_arr_size = 100
|
|
306
|
+
else:
|
|
307
|
+
max_arr_size = -1 # Print all data
|
|
308
|
+
# Title
|
|
309
|
+
if title is None:
|
|
310
|
+
title = truncate(repr(data_in))
|
|
311
|
+
# Displaying inline
|
|
312
|
+
details_style = ""
|
|
313
|
+
if display_inline is True:
|
|
314
|
+
details_style = "style='display: inline;'"
|
|
315
|
+
|
|
316
|
+
if isinstance(data_in, dict):
|
|
317
|
+
contents, _ = _dict2html_tree(data_in, open_default, fields, max_arr_size)
|
|
318
|
+
elif isinstance(data_in, list):
|
|
319
|
+
contents, _ = _list2html_tree(data_in, open_default, fields, max_arr_size)
|
|
320
|
+
else:
|
|
321
|
+
contents = _item2html_tree("", data_in, open_default, fields, max_arr_size)
|
|
322
|
+
return (
|
|
323
|
+
f"<details {openstr} {details_style}>\n"
|
|
324
|
+
' <summary style="display:list-item; outline:none;">\n'
|
|
325
|
+
f" <tt>{title}</tt>\n"
|
|
326
|
+
" </summary>\n"
|
|
327
|
+
' <div style="padding-left:10px; padding-bottom:5px;">\n'
|
|
328
|
+
' <table style="max-width:100%;">\n'
|
|
329
|
+
f"{contents}\n"
|
|
330
|
+
" </table>\n </div>\n</details>\n"
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _item2html_tree(name, item, open_default, fields, max_arr_size):
|
|
335
|
+
if isinstance(item, (dict, list)):
|
|
336
|
+
_fields = remove_name_from_fields(name, fields)
|
|
337
|
+
if isinstance(item, dict):
|
|
338
|
+
content, size = _dict2html_tree(item, open_default, _fields, max_arr_size)
|
|
339
|
+
else:
|
|
340
|
+
content, size = _list2html_tree(item, open_default, _fields, max_arr_size)
|
|
341
|
+
value = _collaps_item(item, content, open_str(name, open_default, fields))
|
|
342
|
+
if isinstance(name, str):
|
|
343
|
+
name = f"'{name}'"
|
|
344
|
+
name = f"{name} |{size}| :"
|
|
345
|
+
else:
|
|
346
|
+
if isinstance(name, str):
|
|
347
|
+
name = f"'{name}'"
|
|
348
|
+
name = f"{name} :"
|
|
349
|
+
if isinstance(item, str):
|
|
350
|
+
value = f"'{item}'"
|
|
351
|
+
else:
|
|
352
|
+
value = item
|
|
353
|
+
return _add_HTML_row(name, value)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _add_HTML_row(name, value):
|
|
357
|
+
return (
|
|
358
|
+
f"<tr>"
|
|
359
|
+
f' <td><p style="margin-bottom: 0px; margin-top: 0px;">{name}</p></td>'
|
|
360
|
+
f' <td style="text-align:left;">{value}</td>'
|
|
361
|
+
f"</tr>\n"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _dict2html_tree(dict_in, open_default, fields, max_arr_size):
|
|
366
|
+
out = ""
|
|
367
|
+
for name, item in dict_in.items():
|
|
368
|
+
out += _item2html_tree(name, item, open_default, fields, max_arr_size)
|
|
369
|
+
return out, len(dict_in)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _list2html_tree(list_in, open_default, open_fields, max_arr_size):
|
|
373
|
+
out = ""
|
|
374
|
+
if (
|
|
375
|
+
max_arr_size > 0
|
|
376
|
+
and _is_numeric_array(list_in)
|
|
377
|
+
and np.asarray(list_in).size > max_arr_size
|
|
378
|
+
):
|
|
379
|
+
array = np.asarray(list_in)
|
|
380
|
+
out += _add_HTML_row("min", repr(float(array.min())))
|
|
381
|
+
out += _add_HTML_row("max", repr(float(array.max())))
|
|
382
|
+
size = repr(array.shape).strip("(),")
|
|
383
|
+
else:
|
|
384
|
+
|
|
385
|
+
for iel, el in enumerate(list_in):
|
|
386
|
+
out += _item2html_tree(iel, el, open_default, open_fields, max_arr_size)
|
|
387
|
+
size = len(list_in)
|
|
388
|
+
return out, size
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _is_numeric_array(list_in):
|
|
392
|
+
"""Method to test if a `list` or nested `list`'s only contains `float`'s or `int`'s. Testing by casting to an array and check the resulting `.dtype`.
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
list_in : Any
|
|
397
|
+
Data to test
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
bool
|
|
402
|
+
Flag, `True` means the list is a `list` or nested `list`'s of numbers.
|
|
403
|
+
"""
|
|
404
|
+
try:
|
|
405
|
+
if np.issubdtype(np.asarray(list_in).dtype, np.number):
|
|
406
|
+
return True
|
|
407
|
+
return False
|
|
408
|
+
except:
|
|
409
|
+
return False
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _collaps_item(item, content, open):
|
|
413
|
+
return (
|
|
414
|
+
f"<details {open}>\n"
|
|
415
|
+
' <summary style="display:list-item; outline:none;">\n'
|
|
416
|
+
f" <tt>{truncate(repr(item), 15)}</tt>\n"
|
|
417
|
+
" </summary>\n"
|
|
418
|
+
' <div style="padding-left:10px; padding-bottom:5px;">\n'
|
|
419
|
+
'<table style="max-width:100%;">\n'
|
|
420
|
+
f"{content}\n"
|
|
421
|
+
"</table>\n </div>\n</details>\n"
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def is_open(name, open_default, fields):
|
|
426
|
+
open = open_default
|
|
427
|
+
if fields is not None and any(
|
|
428
|
+
[(name == el[0]) or (el[0] is True) for el in fields if isinstance(el, list)]
|
|
429
|
+
):
|
|
430
|
+
return not open
|
|
431
|
+
return open
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def open_str(name, open_default, fields):
|
|
435
|
+
open = is_open(name, open_default, fields)
|
|
436
|
+
return " open" if open else ""
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def remove_name_from_fields(name, fields):
|
|
440
|
+
if fields is None:
|
|
441
|
+
return None
|
|
442
|
+
out = []
|
|
443
|
+
for el in fields:
|
|
444
|
+
if isinstance(el, list) and ((el[0] == name) or (el[0] is True)):
|
|
445
|
+
if len(el) > 1:
|
|
446
|
+
out.append(el[1:])
|
|
447
|
+
else:
|
|
448
|
+
out.append("")
|
|
449
|
+
else:
|
|
450
|
+
out.append(el)
|
|
451
|
+
return out
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
# From: https://stackoverflow.com/questions/449560/how-do-i-determine-the-size-of-an-object-in-python
|
|
455
|
+
BLACKLIST = type, ModuleType, FunctionType
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def get_data_size(obj):
|
|
459
|
+
"""sum size of object & members."""
|
|
460
|
+
if isinstance(obj, BLACKLIST):
|
|
461
|
+
raise TypeError("getsize() does not take argument of type: " + str(type(obj)))
|
|
462
|
+
seen_ids = set()
|
|
463
|
+
size = 0
|
|
464
|
+
objects = [obj]
|
|
465
|
+
while objects:
|
|
466
|
+
need_referents = []
|
|
467
|
+
for obj in objects:
|
|
468
|
+
if not isinstance(obj, BLACKLIST) and id(obj) not in seen_ids:
|
|
469
|
+
seen_ids.add(id(obj))
|
|
470
|
+
size += sys.getsizeof(obj)
|
|
471
|
+
need_referents.append(obj)
|
|
472
|
+
objects = get_referents(*need_referents)
|
|
473
|
+
return size
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
class json_data_render:
|
|
477
|
+
"""Converting JSON data to a HTML table with collapsible nested list and dict's
|
|
478
|
+
|
|
479
|
+
Parameters
|
|
480
|
+
----------
|
|
481
|
+
data_in : dict, list
|
|
482
|
+
JSON compliant dict and list
|
|
483
|
+
open_default : bool, optional
|
|
484
|
+
Flag for default opening or closing collapsible entries, by default False
|
|
485
|
+
fields : list, bool, optional
|
|
486
|
+
list or list of list of names to open or close (opposed to open_default). `True` means that it should open the root - `False` close the root, by default None
|
|
487
|
+
max_arr_size : int, optional
|
|
488
|
+
Maximum size of numeric arrays to render. Using `np.size(array) > max_arr_size`. Default will be determined based on the size of the data, `max_arr_size=[5, 10, 100]` for data with approx. size of [1000, 100, 10] size 100 arrays. Otherwise `max_array_size=-1` which means to render all arrays.
|
|
489
|
+
|
|
490
|
+
Returns
|
|
491
|
+
-------
|
|
492
|
+
str
|
|
493
|
+
Representation of the data as a HTML table with collapsible entries
|
|
494
|
+
|
|
495
|
+
Raises
|
|
496
|
+
------
|
|
497
|
+
ValueError
|
|
498
|
+
If fields are not a list or None
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
def __init__(self, data_in, open_default=False, fields=None, max_arr_size=None):
|
|
502
|
+
self.open_default = open_default
|
|
503
|
+
self.fields = fields
|
|
504
|
+
self.max_arr_size = max_arr_size
|
|
505
|
+
self.json_data = is_valid_json(data_in, True)
|
|
506
|
+
|
|
507
|
+
def _repr_html_(self):
|
|
508
|
+
return json2html(
|
|
509
|
+
self.json_data, self.open_default, self.fields, self.max_arr_size
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def display_json_data(data_in, open_default=False, fields=None, max_arr_size=None):
|
|
514
|
+
"""Display json like data as an HTML tree
|
|
515
|
+
|
|
516
|
+
Simple wrapper for:
|
|
517
|
+
|
|
518
|
+
display(json_data_render(json_data))
|
|
519
|
+
|
|
520
|
+
Parameters
|
|
521
|
+
----------
|
|
522
|
+
data_in : dict, list
|
|
523
|
+
JSON compliant dict and list
|
|
524
|
+
open_default : bool, optional
|
|
525
|
+
Flag for default opening or closing collapsible entries, by default False
|
|
526
|
+
fields : list, optional
|
|
527
|
+
list or list of list of names to open or close (opposed to open_default). `True` means that it should open the root - `False` close the root, by default None
|
|
528
|
+
max_arr_size : int, optional
|
|
529
|
+
Maximum size of numeric arrays to render. Using `np.size(array) > max_arr_size`. Default will be determined based on the size of the data, `max_arr_size=[5, 10, 100]` for data with approx. size of [1000, 100, 10] size 100 arrays. Otherwise `max_array_size=-1` which means to render all arrays.
|
|
530
|
+
"""
|
|
531
|
+
from IPython.display import display
|
|
532
|
+
|
|
533
|
+
display(json_data_render(data_in, open_default, fields, max_arr_size))
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def read_json(filename, asarray=True, **json_load_kwargs):
|
|
7
|
+
"""Read a json file. Optionally convert data with list of numbers to numpy array.
|
|
8
|
+
|
|
9
|
+
Simple wrapper for:
|
|
10
|
+
|
|
11
|
+
with open(filename, "r") as file:
|
|
12
|
+
out = json.load(file, object_hook=NpDecode_object_hook if asarray else None)
|
|
13
|
+
return out
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
filename : str
|
|
18
|
+
Name of the file to load
|
|
19
|
+
asarray : bool, optional
|
|
20
|
+
Flag for converter list of numbers to numpy array, by default True
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
dist, list
|
|
25
|
+
Data from the json file
|
|
26
|
+
"""
|
|
27
|
+
with open(filename, "r") as file:
|
|
28
|
+
out = json.load(
|
|
29
|
+
file,
|
|
30
|
+
object_hook=JSONNumpyDecode_object_hook if asarray else None,
|
|
31
|
+
**json_load_kwargs
|
|
32
|
+
)
|
|
33
|
+
return out
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def write_json(filename, data, convert_numpy=True, **json_dump_kwargs):
|
|
37
|
+
"""Write JSON compatible data to file. Optionally convert numpy data.
|
|
38
|
+
|
|
39
|
+
Simple wrapper:
|
|
40
|
+
|
|
41
|
+
with open(filename, "w") as file:
|
|
42
|
+
json.dump(data, file, cls=NpEncoder if convert_numpy else None)
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
filename : str
|
|
47
|
+
Name of the JSON file to write
|
|
48
|
+
data : dict, list
|
|
49
|
+
Data to be written to file
|
|
50
|
+
convert_numpy : bool, optional
|
|
51
|
+
Flag for converting numpy data as a part of the writing process, by default True
|
|
52
|
+
"""
|
|
53
|
+
with open(filename, "w") as file:
|
|
54
|
+
json.dump(
|
|
55
|
+
data,
|
|
56
|
+
file,
|
|
57
|
+
cls=JSONNumpyEncoder if convert_numpy else None,
|
|
58
|
+
**json_dump_kwargs
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class JSONNumpyEncoder(json.JSONEncoder):
|
|
63
|
+
"""Encodes numpy types to python buildin
|
|
64
|
+
|
|
65
|
+
Usages:
|
|
66
|
+
|
|
67
|
+
with open("data.json", "w") as file:
|
|
68
|
+
out = json.dump(file, cls=NpEncoder)
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def default(self, obj):
|
|
72
|
+
if isinstance(obj, np.integer):
|
|
73
|
+
return int(obj)
|
|
74
|
+
if isinstance(obj, np.floating):
|
|
75
|
+
return float(obj)
|
|
76
|
+
if isinstance(obj, np.ndarray):
|
|
77
|
+
return obj.tolist()
|
|
78
|
+
if isinstance(obj, np.bool_):
|
|
79
|
+
return bool(obj)
|
|
80
|
+
return super(JSONNumpyEncoder, self).default(obj)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def JSONNumpyDecode_object_hook(obj):
|
|
84
|
+
"""JSON `object_hook` to converter list of numbers to numpy arrays
|
|
85
|
+
|
|
86
|
+
Usages:
|
|
87
|
+
|
|
88
|
+
with open("data.json", "r") as file:
|
|
89
|
+
out = json.load(file, object_hook=NpDecode_object_hook)
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
obj : dict
|
|
94
|
+
JSON compliant dict
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
dict
|
|
99
|
+
Dict with all list of numbers replaced as numpy arrays
|
|
100
|
+
"""
|
|
101
|
+
for name, val in obj.items():
|
|
102
|
+
if isinstance(val, list) and np.issubdtype(np.asarray(val).dtype, np.number):
|
|
103
|
+
obj[name] = np.asarray(val)
|
|
104
|
+
return obj
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def is_valid_json(data, allow_numpy=False):
|
|
108
|
+
"""Verify if data is JSON valid. Optionally (`allow_numpy=True`) it will allow numpy.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
data : dict, list
|
|
113
|
+
Data to verify if is JSON valid
|
|
114
|
+
allow_numpy : bool, optional
|
|
115
|
+
Flag for allowing numpy data, by default False
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
dict,list
|
|
120
|
+
Returns JSON valid data. (If `allow_numpy=True` numpy data will be converted to lists and build-in data types)
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
return json.loads(
|
|
124
|
+
json.dumps(data, cls=JSONNumpyEncoder if allow_numpy else None)
|
|
125
|
+
)
|
|
126
|
+
except:
|
|
127
|
+
return False
|