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
aesoptparam/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from param import *
|
|
2
|
+
|
|
3
|
+
from .parameterized import AESOptParameterized
|
|
4
|
+
from .parameters import (
|
|
5
|
+
AESOptArray,
|
|
6
|
+
AESOptBoolean,
|
|
7
|
+
AESOptInteger,
|
|
8
|
+
AESOptNumber,
|
|
9
|
+
AESOptString,
|
|
10
|
+
ListOfParameterized,
|
|
11
|
+
SubParameterized,
|
|
12
|
+
)
|
|
13
|
+
from .utils import copy_param, copy_param_ref
|
aesoptparam/example.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from aesoptparam import (
|
|
4
|
+
AESOptArray,
|
|
5
|
+
AESOptNumber,
|
|
6
|
+
AESOptParameterized,
|
|
7
|
+
AESOptString,
|
|
8
|
+
Dict,
|
|
9
|
+
ListOfParameterized,
|
|
10
|
+
String,
|
|
11
|
+
SubParameterized,
|
|
12
|
+
copy_param,
|
|
13
|
+
copy_param_ref,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class sub1_class(AESOptParameterized):
|
|
18
|
+
"""Docs sub1"""
|
|
19
|
+
|
|
20
|
+
a = AESOptNumber(5.0, doc="Docs for sub1.a", bounds=(0, 10))
|
|
21
|
+
b = AESOptArray(np.linspace(0, 10, 10), doc="Docs for sub1.b")
|
|
22
|
+
c = AESOptArray(default_ref=".b", doc="Docs for sub1.c")
|
|
23
|
+
e = AESOptArray(
|
|
24
|
+
lambda self: np.full_like(self.b, self.a), shape=".b", doc="Docs for sub1.e"
|
|
25
|
+
)
|
|
26
|
+
f = AESOptArray(default_full=(".b", ".a"), doc="Docs for sub1.d")
|
|
27
|
+
g = AESOptArray(default_full=(".b", 6.0), doc="Docs for sub1.g")
|
|
28
|
+
h = AESOptArray(
|
|
29
|
+
default_interp=(np.linspace(0, 10, 5), ".b", ".c"), doc="Docs for sub1.h"
|
|
30
|
+
)
|
|
31
|
+
i = AESOptString("sub1.Dummy", doc="Docs for sub1.i")
|
|
32
|
+
j = AESOptString(".i", doc="Docs for sub1.j")
|
|
33
|
+
k = AESOptString(lambda self: self.i + "2", doc="Docs for sub1.k")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class sub2_class(AESOptParameterized):
|
|
37
|
+
"""Docs sub2"""
|
|
38
|
+
|
|
39
|
+
a = copy_param_ref(
|
|
40
|
+
sub1_class.param.a, "..sub1.a", update=dict(doc="Docs for sub2.a")
|
|
41
|
+
)
|
|
42
|
+
b = AESOptNumber(default_ref="..a", doc="Docs for sub2.b")
|
|
43
|
+
c = AESOptNumber(default_ref="..sub_list[0].a", doc="Docs for sub2.c")
|
|
44
|
+
d = copy_param_ref(
|
|
45
|
+
sub1_class.param.b, "..sub1.b", update=dict(doc="Docs for sub2.d")
|
|
46
|
+
)
|
|
47
|
+
e = AESOptArray(
|
|
48
|
+
lambda self: (
|
|
49
|
+
None if self.parent_object.sub1.b is None else self.parent_object.sub1.b + 1
|
|
50
|
+
),
|
|
51
|
+
doc="Docs for sub2.e",
|
|
52
|
+
)
|
|
53
|
+
f = AESOptString("..f", doc="Docs for sub2.f")
|
|
54
|
+
g = copy_param_ref(
|
|
55
|
+
sub1_class.param.i, "..sub1.i", update=dict(doc="Docs for sub2.g")
|
|
56
|
+
)
|
|
57
|
+
h = AESOptString("..sub_list[0].f", doc="Docs for sub2.h")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class sub_list_class(AESOptParameterized):
|
|
61
|
+
"""Docs sub_list"""
|
|
62
|
+
|
|
63
|
+
a = AESOptNumber(6.0, doc="Docs for sub_list.a")
|
|
64
|
+
b = AESOptNumber(default_ref="..a", doc="Docs for sub_list.b")
|
|
65
|
+
c = AESOptNumber(default_ref="..sub1.a", doc="Docs for sub_list.c")
|
|
66
|
+
d = AESOptArray(default_ref="..d", doc="Docs for sub_list.d")
|
|
67
|
+
e = AESOptArray(default_ref="..sub1.b", doc="Docs for sub_list.e")
|
|
68
|
+
f = AESOptString(default_ref="..f", doc="Docs for sub_list.f")
|
|
69
|
+
g = AESOptString(default_ref="..sub1.i", doc="Docs for sub_list.g")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class main(AESOptParameterized):
|
|
73
|
+
"""Main object"""
|
|
74
|
+
|
|
75
|
+
version = String("0.0.0", readonly=True, precedence=0.0)
|
|
76
|
+
name = String("Dummy", doc="Main dummy", precedence=0.01)
|
|
77
|
+
a = AESOptNumber(4.0, units="rad/s", doc="Docs for .a", bounds=(0, 10))
|
|
78
|
+
b = AESOptNumber(default_ref=".sub1.a", units="m/s", doc="Docs for .b")
|
|
79
|
+
c = AESOptNumber(default_ref=".sub_list[0].a", doc="Docs for .c")
|
|
80
|
+
d = AESOptArray(
|
|
81
|
+
default_ref=".sub1.b", units="mm/s", doc="Docs for .d", bounds=(0, 10)
|
|
82
|
+
)
|
|
83
|
+
e = AESOptArray(
|
|
84
|
+
np.array([0, 1, 2, 3]),
|
|
85
|
+
shape=4,
|
|
86
|
+
units="mm/s",
|
|
87
|
+
doc="Docs for .d",
|
|
88
|
+
bounds=(0, 10),
|
|
89
|
+
dtype=int,
|
|
90
|
+
)
|
|
91
|
+
f = AESOptString("Dummy", doc="Docs for .f")
|
|
92
|
+
g = AESOptString(".f", doc="Docs for .g")
|
|
93
|
+
h = AESOptString(lambda self: self.f + "2", doc="Docs for .h")
|
|
94
|
+
i = Dict(doc="Docs for .i")
|
|
95
|
+
sub1 = SubParameterized(sub1_class)
|
|
96
|
+
sub2 = SubParameterized(sub2_class)
|
|
97
|
+
sub_list = ListOfParameterized(sub_list_class)
|
|
98
|
+
sub_list2 = ListOfParameterized(
|
|
99
|
+
sub_list_class, default_call=lambda self: [self.add_sub_list2()]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def add_sub_list(self, **params):
|
|
103
|
+
return self.add_ListOfParameterized_item(
|
|
104
|
+
"sub_list", self.param.sub_list.item_type, **params
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def add_sub_list2(self, **params):
|
|
108
|
+
return self.add_ListOfParameterized_item(
|
|
109
|
+
"sub_list2", self.param.sub_list2.item_type, **params
|
|
110
|
+
)
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import param as pm
|
|
6
|
+
from scipy.interpolate import PchipInterpolator
|
|
7
|
+
|
|
8
|
+
from .parameters import Function, ListOfParameterized, Reference
|
|
9
|
+
from .serializer import ASEOptJSONSerialization
|
|
10
|
+
from .utils import read_json, write_json
|
|
11
|
+
from .utils.html_repr import parameterized_repr_html, parameterized_repr_html_class
|
|
12
|
+
from .utils.units import convert_units
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AESOptParameterized(pm.Parameterized):
|
|
16
|
+
"""Base object inheriting from `param.Parameterized`. Adds specific methods for interacting with data in AESOpt models."""
|
|
17
|
+
|
|
18
|
+
interpolator = PchipInterpolator
|
|
19
|
+
|
|
20
|
+
def __init__(self, parent_object=None, **params):
|
|
21
|
+
"""Initialize object with parameters. **params are passed with the .from_dict. The parent_object argument allows nested objects to access data across the full data model"""
|
|
22
|
+
self.parent_object = parent_object
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.from_dict(params)
|
|
25
|
+
|
|
26
|
+
def from_dict(self, dict_in):
|
|
27
|
+
"""Set parameters from `dict`"""
|
|
28
|
+
for key, val in dict_in.items():
|
|
29
|
+
if key in self.param:
|
|
30
|
+
p = self.param[key]
|
|
31
|
+
if hasattr(p, "readonly") and p.readonly:
|
|
32
|
+
if np.all(self[key] != val):
|
|
33
|
+
raise ValueError(
|
|
34
|
+
f"A parameter with readonly has a different value in the dict than currently in the object (given: self.{key}={self[key]}, dict_in['{key}']={val})"
|
|
35
|
+
)
|
|
36
|
+
continue
|
|
37
|
+
if hasattr(self[key], "from_dict"):
|
|
38
|
+
self[key].from_dict(val)
|
|
39
|
+
elif (
|
|
40
|
+
isinstance(self.param[key], pm.List)
|
|
41
|
+
and (self.param[key].item_type is not None)
|
|
42
|
+
and hasattr(self.param[key].item_type, "from_dict")
|
|
43
|
+
):
|
|
44
|
+
for i, el in enumerate(val):
|
|
45
|
+
if len(self[key]) > i:
|
|
46
|
+
self[key][i].from_dict(el)
|
|
47
|
+
else:
|
|
48
|
+
self[key].append(
|
|
49
|
+
self.param[key].item_type(self).from_dict(el)
|
|
50
|
+
)
|
|
51
|
+
elif isinstance(self.param[key], pm.Array) and isinstance(val, list):
|
|
52
|
+
arr = np.asarray(val)
|
|
53
|
+
self[key] = arr
|
|
54
|
+
else:
|
|
55
|
+
self[key] = val
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
def as_dict(self, onlychanged=True, as_refs=False, as_funcs=False) -> dict:
|
|
59
|
+
"""Get object as dict. It also works for nested data structure, references and functions.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
onlychanged : bool, optional
|
|
64
|
+
Flag for only returning data that has been changed compared to the default, by default True
|
|
65
|
+
as_refs : bool, optional
|
|
66
|
+
Flag for returning the `Reference` instance instead of the values, by default False
|
|
67
|
+
as_funcs : bool, optional
|
|
68
|
+
Flag for returning the `Function` instance instead of the values, by default False
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
dict
|
|
73
|
+
Object data as a dict
|
|
74
|
+
"""
|
|
75
|
+
return self._as_dict(
|
|
76
|
+
onlychanged=onlychanged, serialize=False, as_refs=as_refs, as_funcs=as_funcs
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def as_serial(self, onlychanged=True, as_refs=True, as_funcs=True) -> dict:
|
|
80
|
+
"""Get instance as a serializable dict. It returns a `dict` with native python data types (e.g. `list`, `float`, `int`, `str`), which can be written to file with `json`, `yaml` and `toml`.
|
|
81
|
+
It will also convert references (to `$ref *ref*`) and functions (to `$function *function string*`)
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
onlychanged : bool, optional
|
|
86
|
+
Flag for only returning data that has been changed compared to the default, by default True
|
|
87
|
+
as_refs : bool, optional
|
|
88
|
+
Flag for returning the value from references or functions, by default True
|
|
89
|
+
as_funcs : bool, optional
|
|
90
|
+
Flag for returning the `Function` instance instead of the values, by default False
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
dict
|
|
95
|
+
Object data as a dict
|
|
96
|
+
"""
|
|
97
|
+
return self._as_dict(
|
|
98
|
+
onlychanged=onlychanged, serialize=True, as_refs=as_refs, as_funcs=as_funcs
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def _as_dict(
|
|
102
|
+
self, onlychanged=True, serialize=False, as_refs=False, as_funcs=False
|
|
103
|
+
):
|
|
104
|
+
out = dict()
|
|
105
|
+
|
|
106
|
+
if onlychanged:
|
|
107
|
+
vals = self._param__private.values
|
|
108
|
+
else:
|
|
109
|
+
vals = self.param.values()
|
|
110
|
+
vals.update(self._param__private.values)
|
|
111
|
+
|
|
112
|
+
for key, val in vals.items():
|
|
113
|
+
p = self.param[key] # Parameter instance
|
|
114
|
+
if (key == "name") and (
|
|
115
|
+
p.doc == "\n String identifier for this object."
|
|
116
|
+
):
|
|
117
|
+
continue
|
|
118
|
+
if onlychanged:
|
|
119
|
+
if (val is None) or (val is p.default):
|
|
120
|
+
continue
|
|
121
|
+
elif (
|
|
122
|
+
isinstance(val, np.ndarray)
|
|
123
|
+
and isinstance(p.default, np.ndarray)
|
|
124
|
+
and np.all(p.default.shape == val.shape)
|
|
125
|
+
and np.allclose(val, p.default)
|
|
126
|
+
):
|
|
127
|
+
continue
|
|
128
|
+
if hasattr(val, "_as_dict"):
|
|
129
|
+
out[key] = val._as_dict(
|
|
130
|
+
onlychanged=onlychanged,
|
|
131
|
+
serialize=serialize,
|
|
132
|
+
as_refs=as_refs,
|
|
133
|
+
as_funcs=as_funcs,
|
|
134
|
+
)
|
|
135
|
+
if not out[key]:
|
|
136
|
+
out.pop(key)
|
|
137
|
+
elif isinstance(val, list) and len(val) > 0 and hasattr(val[0], "_as_dict"):
|
|
138
|
+
out[key] = val.copy()
|
|
139
|
+
for iel, el in enumerate(val):
|
|
140
|
+
out[key][iel] = el._as_dict(
|
|
141
|
+
onlychanged=onlychanged,
|
|
142
|
+
serialize=serialize,
|
|
143
|
+
as_refs=as_refs,
|
|
144
|
+
as_funcs=as_funcs,
|
|
145
|
+
)
|
|
146
|
+
if not out[key][iel]:
|
|
147
|
+
out[key][iel] = None
|
|
148
|
+
if all([el is None for el in out[key]]):
|
|
149
|
+
out.pop(key)
|
|
150
|
+
elif isinstance(val, Reference) and as_refs:
|
|
151
|
+
out[key] = val
|
|
152
|
+
elif isinstance(val, Function) and as_funcs:
|
|
153
|
+
out[key] = val
|
|
154
|
+
else:
|
|
155
|
+
_val = self[key]
|
|
156
|
+
out[key] = _val.copy() if hasattr(_val, "copy") else _val
|
|
157
|
+
|
|
158
|
+
if serialize and (key in out):
|
|
159
|
+
if isinstance(out[key], np.ndarray):
|
|
160
|
+
out[key] = out[key].tolist()
|
|
161
|
+
elif isinstance(out[key], (Reference, Function)):
|
|
162
|
+
out[key] = str(out[key])
|
|
163
|
+
return out
|
|
164
|
+
|
|
165
|
+
def validate_array_shapes(self):
|
|
166
|
+
"""Validate that all arrays with a .shape attribute is consistent with this shape. Will also check nested objects."""
|
|
167
|
+
for name, param in self.param.objects().items():
|
|
168
|
+
if hasattr(param, "shape") and (param.shape is not None):
|
|
169
|
+
shape_ref = self.get_shape_ref(param)
|
|
170
|
+
if not np.all(self[name].shape == shape_ref):
|
|
171
|
+
raise ValueError(
|
|
172
|
+
f"For {self.nested_instance_name} the shape of {name} do not match {param.shape} ({name}.shape={self[name].shape}, shape_ref={shape_ref})"
|
|
173
|
+
)
|
|
174
|
+
elif isinstance(param, ListOfParameterized):
|
|
175
|
+
for el in self[name]:
|
|
176
|
+
if hasattr(el, "validate_array_shapes"):
|
|
177
|
+
el.validate_array_shapes()
|
|
178
|
+
elif hasattr(self[name], "validate_array_shapes"):
|
|
179
|
+
self[name].validate_array_shapes()
|
|
180
|
+
|
|
181
|
+
def get_shape_ref(self, param):
|
|
182
|
+
if isinstance(param.shape, tuple):
|
|
183
|
+
shape_ref = tuple()
|
|
184
|
+
for el in param.shape:
|
|
185
|
+
if isinstance(el, (Reference, str)):
|
|
186
|
+
if not isinstance(self[el], np.ndarray):
|
|
187
|
+
return None
|
|
188
|
+
shape_ref += self[el].shape
|
|
189
|
+
else:
|
|
190
|
+
shape_ref += (el,)
|
|
191
|
+
elif isinstance(param.shape, Reference):
|
|
192
|
+
if isinstance(self[param.shape], np.ndarray):
|
|
193
|
+
shape_ref = self[param.shape].shape
|
|
194
|
+
else:
|
|
195
|
+
return None
|
|
196
|
+
else:
|
|
197
|
+
# Default to int
|
|
198
|
+
shape_ref = (param.shape,)
|
|
199
|
+
return shape_ref
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def nested_instance_name(self):
|
|
203
|
+
"""Nested instance name"""
|
|
204
|
+
if self.has_parent():
|
|
205
|
+
return self.parent_object.nested_instance_name + "." + self.name
|
|
206
|
+
return self.name
|
|
207
|
+
|
|
208
|
+
def interp(self, x, xp, yp, **interp_kwargs):
|
|
209
|
+
"""1D interpolation using SciPy interpolator (default to [`PChipInterpolator`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html#scipy.interpolate.PchipInterpolator)). Arguments (`x`, `xp`, `yp`) can either be strings (object-paths) or numpy arrays."""
|
|
210
|
+
_x = x if isinstance(x, np.ndarray) else self[x]
|
|
211
|
+
_xp = xp if isinstance(xp, np.ndarray) else self[xp]
|
|
212
|
+
_yp = yp if isinstance(yp, np.ndarray) else self[yp]
|
|
213
|
+
if any([el is None for el in [_x, _xp, _yp]]):
|
|
214
|
+
return
|
|
215
|
+
return self.interpolator(_xp, _yp, **interp_kwargs)(_x)
|
|
216
|
+
|
|
217
|
+
def _repr_html_(self):
|
|
218
|
+
return parameterized_repr_html(self, True, max_arr_size=50)
|
|
219
|
+
|
|
220
|
+
def __getitem__(self, key):
|
|
221
|
+
if isinstance(key, str):
|
|
222
|
+
if ("." in key) or ("[" in key):
|
|
223
|
+
path_list = path_to_path_list(key)
|
|
224
|
+
out = self
|
|
225
|
+
previous_empty = False
|
|
226
|
+
for _key in path_list:
|
|
227
|
+
if isinstance(_key, str) and _key == "":
|
|
228
|
+
if previous_empty:
|
|
229
|
+
out = out.parent_object
|
|
230
|
+
previous_empty = False
|
|
231
|
+
else:
|
|
232
|
+
previous_empty = True
|
|
233
|
+
else:
|
|
234
|
+
if isinstance(_key, int) and len(out) <= _key:
|
|
235
|
+
# Return none if array is shorter
|
|
236
|
+
return None
|
|
237
|
+
out = out[_key]
|
|
238
|
+
previous_empty = False
|
|
239
|
+
return out
|
|
240
|
+
return getattr(self, key)
|
|
241
|
+
elif isinstance(key, Reference):
|
|
242
|
+
return self[key.path]
|
|
243
|
+
super().__getattribute__(key)
|
|
244
|
+
|
|
245
|
+
def __setitem__(self, key, val):
|
|
246
|
+
if isinstance(key, str):
|
|
247
|
+
return setattr(self, key, val)
|
|
248
|
+
super().__setattr__(key, val)
|
|
249
|
+
|
|
250
|
+
def get_val(self, name, units=None):
|
|
251
|
+
"""Get a value with other units"""
|
|
252
|
+
self._validate_has_units(name)
|
|
253
|
+
return convert_units(self[name], self.param[name].units, units)
|
|
254
|
+
|
|
255
|
+
def set_val(self, name, val, units=None):
|
|
256
|
+
"""Get a value with other units"""
|
|
257
|
+
self._validate_has_units(name)
|
|
258
|
+
self[name] = convert_units(val, units, self.param[name].units)
|
|
259
|
+
|
|
260
|
+
def _validate_has_units(self, name):
|
|
261
|
+
if not hasattr(self.param[name], "units"):
|
|
262
|
+
raise RuntimeError(
|
|
263
|
+
f"parameter with name: {name} do not have units (the parameter do not have `units` attribute, type(.param[name])={type(self.param[name])})"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def add_ListOfParameterized_item(self, LOP_name, item_type, **kwargs):
|
|
267
|
+
"""Utility method to add Parameterized entries to a ListOfParameterized. It insure that the parent object is added. It is recommenced that this method is wrapped by a more specific method like `add_XX(self, **kwargs)` where the `LOP_name` and `item_type` is provided statically."""
|
|
268
|
+
# Instantiate item_type
|
|
269
|
+
item = item_type(parent_object=self, **kwargs)
|
|
270
|
+
# Append the item to the list of ListOfParameterized
|
|
271
|
+
if not LOP_name in self._param__private.values:
|
|
272
|
+
self._param__private.values[LOP_name] = []
|
|
273
|
+
self._param__private.values[LOP_name].append(item)
|
|
274
|
+
# Return the item that is added
|
|
275
|
+
return item
|
|
276
|
+
|
|
277
|
+
def as_json(
|
|
278
|
+
self, onlychanged=True, as_refs=True, as_funcs=True, **kwargs_json_dumps
|
|
279
|
+
):
|
|
280
|
+
"""Get data as a JSON string. `onlychanged` is a flag for only getting non default values."""
|
|
281
|
+
return json.dumps(
|
|
282
|
+
self.as_serial(onlychanged=onlychanged, as_refs=as_refs, as_funcs=as_funcs),
|
|
283
|
+
**kwargs_json_dumps,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
def write_json(
|
|
287
|
+
self,
|
|
288
|
+
filename,
|
|
289
|
+
onlychanged=True,
|
|
290
|
+
as_refs=True,
|
|
291
|
+
as_funcs=True,
|
|
292
|
+
**kwargs_json_dump,
|
|
293
|
+
):
|
|
294
|
+
"""Write data to a JSON file. `onlychanged` is a flag for only getting non default values."""
|
|
295
|
+
with open(filename, "w") as file:
|
|
296
|
+
json.dump(
|
|
297
|
+
self.as_serial(
|
|
298
|
+
onlychanged=onlychanged, as_refs=as_refs, as_funcs=as_funcs
|
|
299
|
+
),
|
|
300
|
+
file,
|
|
301
|
+
**kwargs_json_dump,
|
|
302
|
+
)
|
|
303
|
+
return self
|
|
304
|
+
|
|
305
|
+
def read_json(self, filename, asarray=True):
|
|
306
|
+
"""Read data from a JSON file."""
|
|
307
|
+
data = read_json(filename, asarray)
|
|
308
|
+
data.pop("$schema", None)
|
|
309
|
+
self.from_dict(data)
|
|
310
|
+
return self
|
|
311
|
+
|
|
312
|
+
def as_json_schema(self, safe=False, subset=None, skip_default_name=True) -> dict:
|
|
313
|
+
"""Get object as a JSON schema
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
safe : bool, optional
|
|
318
|
+
Flag for getting safe schema, by default False
|
|
319
|
+
subset : list, optional
|
|
320
|
+
List of names to skip, by default None
|
|
321
|
+
skip_default_name : bool, optional
|
|
322
|
+
Flag for skipping the default name when creating the schema, by default True
|
|
323
|
+
|
|
324
|
+
Returns
|
|
325
|
+
-------
|
|
326
|
+
dict
|
|
327
|
+
JSON Schema
|
|
328
|
+
"""
|
|
329
|
+
return ASEOptJSONSerialization.schema(self, safe, subset, skip_default_name)
|
|
330
|
+
|
|
331
|
+
def write_json_schema(
|
|
332
|
+
self,
|
|
333
|
+
filename,
|
|
334
|
+
safe=False,
|
|
335
|
+
subset=None,
|
|
336
|
+
skip_default_name=True,
|
|
337
|
+
**kwargs_json_dump,
|
|
338
|
+
):
|
|
339
|
+
"""Write object as a JSON schema file
|
|
340
|
+
|
|
341
|
+
Parameters
|
|
342
|
+
----------
|
|
343
|
+
filename : str,Path
|
|
344
|
+
Filename for the JSON schema
|
|
345
|
+
safe : bool, optional
|
|
346
|
+
Flag for getting safe schema, by default False
|
|
347
|
+
subset : list, optional
|
|
348
|
+
List of names to skip, by default None
|
|
349
|
+
skip_default_name : bool, optional
|
|
350
|
+
Flag for skipping the default name when creating the schema, by default True
|
|
351
|
+
|
|
352
|
+
Returns
|
|
353
|
+
-------
|
|
354
|
+
self
|
|
355
|
+
"""
|
|
356
|
+
with open(filename, "w") as file:
|
|
357
|
+
json.dump(
|
|
358
|
+
self.as_json_schema(safe, subset, skip_default_name),
|
|
359
|
+
file,
|
|
360
|
+
**kwargs_json_dump,
|
|
361
|
+
)
|
|
362
|
+
return self
|
|
363
|
+
|
|
364
|
+
def has_parent(self):
|
|
365
|
+
return not self.parent_object is None
|
|
366
|
+
|
|
367
|
+
def display(self, open=True, title=None, max_arr_size=50):
|
|
368
|
+
"""Method to display the settings and documentation of the current instance. Similar to just rendering the by last entry of the cell but allows a little more control
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
open : bool, optional
|
|
373
|
+
Flag for opening or closing root the HTML table, by default True
|
|
374
|
+
title : str, optional
|
|
375
|
+
The string that will be shown as the root of the object, by default None
|
|
376
|
+
max_arr_size : int, optional
|
|
377
|
+
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.
|
|
378
|
+
"""
|
|
379
|
+
from IPython.display import display
|
|
380
|
+
|
|
381
|
+
display(parameterized_repr_html_class(self, open, title, max_arr_size))
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def path_to_path_list(path):
|
|
385
|
+
"""Converts an object path string to a `path_list`.
|
|
386
|
+
|
|
387
|
+
Parameters
|
|
388
|
+
----------
|
|
389
|
+
path : str
|
|
390
|
+
Object path (e.g. `"key1.key2.key3[0].key4"`)
|
|
391
|
+
|
|
392
|
+
Returns
|
|
393
|
+
-------
|
|
394
|
+
list
|
|
395
|
+
List of keys and indices (e.g. `["key1","key2","key3",0,"key4"]`)
|
|
396
|
+
|
|
397
|
+
Raises
|
|
398
|
+
------
|
|
399
|
+
ValueError
|
|
400
|
+
If indices are not integers (e.g. `key1[key3]` will fail)
|
|
401
|
+
"""
|
|
402
|
+
path_list = []
|
|
403
|
+
for name in path.split(".") if path.split(".") else [path]:
|
|
404
|
+
if "[" in name:
|
|
405
|
+
names = re.findall(r"([^\[\]]+)", name)
|
|
406
|
+
if len(names) > 1:
|
|
407
|
+
path_list.append(names[0])
|
|
408
|
+
names = names[1:]
|
|
409
|
+
for index in names:
|
|
410
|
+
if not index.replace("-", "").replace("+", "").isdigit():
|
|
411
|
+
raise ValueError(
|
|
412
|
+
f"Indices need to integers: index={index} (name={name}, path={path})"
|
|
413
|
+
)
|
|
414
|
+
path_list.append(int(index))
|
|
415
|
+
else:
|
|
416
|
+
path_list.append(name)
|
|
417
|
+
return path_list
|