Skip to content

Commit 648ae61

Browse files
committed
Merge branch 'main' of https://github.com/sandialabs/pyscan into add-json-converter
2 parents a1f1700 + c9906d7 commit 648ae61

14 files changed

+249
-9
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
## [0.5.4](https://github.com/sandialabs/pyscan/compare/v0.5.3...v0.5.4) (2024-07-09)
2+
3+
4+
### Bug Fixes
5+
6+
* **core:** added a json converter class in json_encoder.py to pyscan/general. This is now implemented in the save_metadata method of abstract_experiment.py which enables numpy values to be used as data inputs before saving. The converter changes the numpy values to standard python values and no longer throws the same type error as before. ([c2c2b8f](https://github.com/sandialabs/pyscan/commit/c2c2b8ffb3f8d1860f6dc6612b2c83eddc21a28f))
7+
* **core:** added working json converter for runinfo and devices metadata now implemented in abstract experiment's save_metadata method. ([11f43a3](https://github.com/sandialabs/pyscan/commit/11f43a3c247dd4294d079ffd20b360572ffc3ed8))
8+
* **core:** corrected the issue plesiopterys identified with saving numpy data types and consolidated the json converter added in the last commit to the pre existing recursive_to_dict function which can now handle numpy data types for saving. ([fb66ad8](https://github.com/sandialabs/pyscan/commit/fb66ad8727acfd33b6f59feef6b7a68d023d052f))
9+
* **core:** fixed issue causing multiple experiments run with the same runinfo to fail. These sequential experiments would improperly double runinfo.measured by appending the same values to it more than once. Then when data was tried to be preallocated in abstract expt it would fail. ([cb093a2](https://github.com/sandialabs/pyscan/commit/cb093a25c5e86edb62b2a22ed7eab91fa73a1956))
10+
* **core:** Fixed the issue with saving if experiments are run 'too fast'. Will now handle ultra fast experiments (up to a micro second or more) which was tested with demo nb 1 using a dt of 0.000000001 and consecutive experiments. ([bba1bca](https://github.com/sandialabs/pyscan/commit/bba1bcac7561a8f9e03083d3b12951223ccba4d4))
11+
* **core:** updated experiment.py to reinitialize runinfo.measured as an empty list before populating at the beginning of every experiment run. This was causing issues with running subsequent experiments with the same runinfo, and is necessary to prevent runinfo.measured from being reused if runinfo.measure_function changed between runs. ([bbc1be8](https://github.com/sandialabs/pyscan/commit/bbc1be8958081385c4cfe3d23f5ab6eae83b8c82))
12+
13+
14+
### Reverts
15+
16+
* Revert "fix(core): added a json converter class in json_encoder.py to pyscan/general. This is now implemented in the save_metadata method of abstract_experiment.py which enables numpy values to be used as data inputs before saving. The converter changes the numpy values to standard python values and no longer throws the same type error as before." ([30dbdd5](https://github.com/sandialabs/pyscan/commit/30dbdd5c25186ee3278894588b9a9121a354d7eb))
17+
* Revert "fix(core): corrected the issue plesiopterys identified with saving numpy data types and consolidated the json converter added in the last commit to the pre existing recursive_to_dict function which can now handle numpy data types for saving." ([30c601d](https://github.com/sandialabs/pyscan/commit/30c601d6b2db2f3a8aa66debedbcbc5b2a1e7f70))
18+
* Revert "chore(core): removed old import from abstract_experiment." ([9d7a10b](https://github.com/sandialabs/pyscan/commit/9d7a10bc51932f65bc8bcdba3a35af651f681dbd))
19+
* Revert "chore(core): fix: fixed misuse of np.array n recursive_to_dict that was causing a type error." ([a56704d](https://github.com/sandialabs/pyscan/commit/a56704d650242ca73d9b3b988e50d64806fbb572))
20+
* Revert "fix(core): added working json converter for runinfo and devices metadata now implemented in abstract experiment's save_metadata method." ([0d122b0](https://github.com/sandialabs/pyscan/commit/0d122b0d20b999797e136728ca792c092a06adeb))
21+
* Revert "docs(general): added doc string to json_encoder.py CustomJSONEncoder class." ([1224b06](https://github.com/sandialabs/pyscan/commit/1224b06b573e94347e983ba7fa4156d6b27d97c7))
22+
* Revert "chore(core): removed no longer used recursive_to_dict import from abstract expt." ([7d5b6e9](https://github.com/sandialabs/pyscan/commit/7d5b6e91487a310b8ef15a8000b9bcabb38cdbae))
23+
* Revert "refactor(general): replaced recursive_to_item_attribute with json decoder item_attribute_object_hook." ([6dcfdc1](https://github.com/sandialabs/pyscan/commit/6dcfdc1b01811f81fc5e969addce0fb479595521))
24+
* Revert "chore(general): updated the general __init__.py to account for the file changes from previous commits and import successfully with a new order since itemattribute is used in other pyscan/general modules now." ([27ae91c](https://github.com/sandialabs/pyscan/commit/27ae91c7a1495e05e7887897972ae94ddef886c9))
25+
* Revert "chore(general): fixed improper spelling in the json_decoder." ([205c33a](https://github.com/sandialabs/pyscan/commit/205c33ac3071adfd3c942c7a65258054baf4d67a))
26+
* Revert "chore(general): fixed improper spelling in the json_decoder." ([6e5b788](https://github.com/sandialabs/pyscan/commit/6e5b788fe880b43df8fe30ec9e637e6af8b6f3e0))
27+
* Revert "chore(general): fixed error breaking pytests with decoder referencing np.float_ which was removed in numpy 2.0." ([0886669](https://github.com/sandialabs/pyscan/commit/0886669c34b46721029ed4c810ea9fc2a04c8342))
28+
* Revert "chore(general): fixed error breaking pytests with decoder referencing np.float_ which was removed in numpy 2.0." ([a32e84d](https://github.com/sandialabs/pyscan/commit/a32e84d3a5c5524d53e7b79aa7d48085e160ada2))
29+
30+
31+
132
## [0.5.3](https://github.com/sandialabs/pyscan/compare/v0.5.2...v0.5.3) (2024-06-18)
233

334

VERSION.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "0.5.3"
2+
"version": "0.5.4"
33
}

pyscan/general/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# objects
22
from .item_attribute import ItemAttribute
3-
from .json_encoder import PyscanJSONEncoder
3+
from .pyscan_json_encoder import PyscanJSONEncoder
44

55
# methods
66
from .d_range import drange
@@ -12,4 +12,4 @@
1212
from .set_difference import set_difference
1313
from .stack_or_append import stack_or_append
1414
from .get_pyscan_version import get_pyscan_version
15-
from .json_decoder import PyscanJSONDecoder
15+
from .pyscan_json_decoder import PyscanJSONDecoder
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# -*- coding: utf-8 -*-
2+
import numpy as np
3+
4+
5+
def recursive_to_dict(obj_dict):
6+
'''
7+
Recursive function that converts metadata in runinfo and devices into
8+
serializable object for saving
9+
10+
Parameters
11+
----------
12+
obj_dict : :class:`~pyscan.general.itemattribute.ItemAttribute`
13+
runinfo or devices object
14+
'''
15+
new_dict = {}
16+
17+
for key, value in obj_dict.items():
18+
# print(key, value)
19+
# is method/function
20+
if key in ['logger', 'expt_thread', 'data_path',
21+
'instrument', 'module_id_string', 'spec']:
22+
pass
23+
elif hasattr(value, '__call__'):
24+
new_dict[key] = value.__name__
25+
elif isinstance(value, str):
26+
new_dict[key] = value
27+
# is a dict
28+
elif isinstance(value, dict):
29+
new_dict[key] = recursive_to_dict(value)
30+
# if it is an np array
31+
elif isinstance(value, np.ndarray):
32+
new_dict[key] = value.tolist()
33+
# is an iterator
34+
elif hasattr(value, "__iter__"):
35+
new_dict[key] = list(value)
36+
# is an object
37+
elif hasattr(value, "__dict__"):
38+
new_dict[key] = recursive_to_dict(value.__dict__)
39+
# anything else
40+
else:
41+
new_dict[key] = value
42+
# maybe pass this, but test first
43+
44+
return new_dict
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding: utf-8 -*-
2+
from .item_attribute import ItemAttribute
3+
4+
5+
def recursive_to_itemattribute(data):
6+
'''
7+
Recursive function that converts serialized metadata into an
8+
ItemAttribute object
9+
10+
Parameters
11+
----------
12+
data : dict
13+
dictionary
14+
15+
Returns
16+
-------
17+
:class:`.ItemAttribute`
18+
'''
19+
20+
new_data = ItemAttribute()
21+
22+
for key, value in data.items():
23+
if isinstance(value, dict):
24+
new_data[key] = recursive_to_itemattribute(value)
25+
else:
26+
new_data[key] = value
27+
28+
return new_data

pyscan/measurement/abstract_experiment.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pyscan.general import (ItemAttribute,
99
is_list_type)
1010
from pyscan.measurement.scans import PropertyScan, RepeatScan
11-
from pyscan.general.json_encoder import PyscanJSONEncoder
11+
from pyscan.general.pyscan_json_encoder import PyscanJSONEncoder
1212

1313

1414
class AbstractExperiment(ItemAttribute):
@@ -160,7 +160,16 @@ def check_runinfo(self):
160160
if num_repeat_scans > 1:
161161
assert False, "More than one repeat scan detected. This is not allowed."
162162

163-
self.runinfo.long_name = strftime("%Y%m%dT%H%M%S")
163+
base_name = strftime("%Y%m%dT%H%M%S")
164+
save_path = self.runinfo.data_path / '{}.hdf5'.format(base_name)
165+
count = 0
166+
167+
while save_path.exists():
168+
count += 1
169+
save_path = self.runinfo.data_path / f'{base_name}-{count}.hdf5'
170+
171+
self.runinfo.long_name = save_path.stem
172+
164173
self.runinfo.short_name = self.runinfo.long_name[8:]
165174

166175
self.runinfo.check()

pyscan/measurement/experiment.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def generic_experiment(self):
8282
self.runinfo.t3[indicies] = (datetime.now()).timestamp()
8383

8484
if np.all(np.array(self.runinfo.indicies) == 0):
85+
self.runinfo.measured = []
8586
for key, value in data.items():
8687
self.runinfo.measured.append(key)
8788
self.preallocate(data)
@@ -172,6 +173,7 @@ def average_experiment(self):
172173

173174
# if on the first row of data, log the data names in self.runinfo.measured
174175
if np.all(np.array(self.runinfo.indicies) == 0):
176+
self.runinfo.measured = []
175177
for key, value in data.items():
176178
self.runinfo.measured.append(key)
177179
self.preallocate(data)

pyscan/measurement/load_experiment.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import pickle
44
import json
55
from pathlib import Path
6-
from pyscan.general import ItemAttribute
7-
from pyscan.general.json_decoder import PyscanJSONDecoder
6+
from pyscan.general.pyscan_json_decoder import PyscanJSONDecoder
7+
from pyscan.general.item_attribute import ItemAttribute
88

99

1010
def load_experiment(file_name):
@@ -54,6 +54,8 @@ def load_experiment(file_name):
5454

5555
elif data_version == 0.2:
5656
expt = ItemAttribute()
57+
expt.runinfo = ItemAttribute()
58+
expt.devices = ItemAttribute()
5759

5860
f = h5py.File('{}'.format(file_name), 'r')
5961
expt.runinfo = json.loads(f.attrs['runinfo'], cls=PyscanJSONDecoder)

0 commit comments

Comments
 (0)