Data set examples¶
Basic example¶
Source code :
# -*- coding: utf-8 -*-
import guidata
import guidata.dataset as gds
# Note: the following line is not required if a QApplication has already been created
_app = guidata.qapplication()
class Processing(
gds.DataSet,
title="Processing Parameters",
comment="This comment concerns this class of parameters, and may be overriden "
"when calling the constructor by passing a comment argument. That is the same for "
"the title.",
):
"""Example"""
a = gds.FloatItem("Parameter #1", default=2.3)
b = gds.IntItem("Parameter #2", min=0, max=10, default=5)
type = gds.ChoiceItem("Processing algorithm", ("type 1", "type 2", "type 3"))
param = Processing() # Default title and comment are used if not provided here
param.edit()
print(param) # Showing param contents
param.b = 4 # Modifying item value
param.view()
# Alternative way for creating a DataSet instance:
param = Processing.create(a=7.323, b=4)
print(param)
Other examples¶
A lot of examples are available in the guidata test module
from guidata import tests
tests.run()
The two lines above execute the guidata test launcher :
All guidata items demo¶
import atexit
import datetime
import shutil
import tempfile
from enum import Enum
import numpy as np
import guidata.dataset as gds
from guidata.config import _
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
# Creating temporary files and registering cleanup functions
TEMPDIR = tempfile.mkdtemp(prefix="test_")
atexit.register(shutil.rmtree, TEMPDIR)
FILE_ETA = tempfile.NamedTemporaryFile(suffix=".eta", dir=TEMPDIR)
atexit.register(FILE_ETA.close)
FILE_CSV = tempfile.NamedTemporaryFile(suffix=".csv", dir=TEMPDIR)
atexit.register(FILE_CSV.close)
class ImageTypes(Enum):
"""Image types."""
#: Image filled with zeros
ZEROS = _("Zeros")
#: Empty image (filled with data from memory state)
EMPTY = _("Empty")
#: Image filled with random data (uniform law)
UNIFORMRANDOM = _("Random (uniform law)")
#: Image filled with random data (normal law)
NORMALRANDOM = _("Random (normal law)")
#: 2D Gaussian image
GAUSS = _("Gaussian")
#: Bilinear form image
RAMP = _("2D ramp")
class FilteringMethod(gds.LabeledEnum):
"""LabeledEnum example with invariant keys and UI labels."""
GAUSSIAN = "gaussian", _("Gaussian filter")
MEDIAN = "median", _("Median filter")
SOBEL = "sobel", _("Sobel edge detection")
LAPLACIAN = "laplacian", _("Laplacian filter")
BILATERAL = "bilateral", _("Bilateral filter")
MORPHOLOGICAL = "morphological" # Uses key as label
class ThresholdMode(gds.LabeledEnum):
"""Another LabeledEnum example."""
OTSU = "otsu_method", _("Otsu's method")
ADAPTIVE = "adaptive_mean", _("Adaptive mean")
GLOBAL = "global_threshold", _("Global threshold")
TRIANGLE = "triangle_algorithm", _("Triangle algorithm")
class Parameters(gds.DataSet):
"""
DataSet test
The following text is the DataSet 'comment': <br>Plain text or
<b>rich text<sup>2</sup></b> are both supported,
as well as special characters (α, β, γ, δ, ...)
"""
dir = gds.DirectoryItem("Directory", default=TEMPDIR)
preview = gds.TextItem("File names preview", default="-")
option = gds.ChoiceItem("Option", (("1", "first choice"), ("2", "second choice")))
fname = gds.FileOpenItem("Open file", ("csv", "eta"), FILE_CSV.name)
fnames = gds.FilesOpenItem("Open files", "csv", [FILE_CSV.name])
fname_s = gds.FileSaveItem("Save file", "eta", FILE_ETA.name)
string = gds.StringItem("String", default="default string !?")
text = gds.TextItem("Text", default="default\nmultiline\ntext")
float_slider = gds.FloatItem(
"Float (with slider)", default=0.5, min=0, max=1, step=0.01, slider=True
)
integer = gds.IntItem("Integer", default=5, min=3, max=16, slider=True).set_pos(
col=1
)
dtime = gds.DateTimeItem("Date/time", default=datetime.datetime(2010, 10, 10))
date = gds.DateItem("Date", default=datetime.date(2010, 10, 10)).set_pos(col=1)
bool1 = gds.BoolItem("Boolean option without label")
bool2 = gds.BoolItem("Boolean option with label", "Label")
_bg = gds.BeginGroup("A sub group")
color = gds.ColorItem("Color", default="red")
choice1 = gds.ChoiceItem(
"Single choice 1",
[("16", "first choice"), ("32", "second choice"), ("64", "third choice")],
)
choice2 = gds.ChoiceItem("Image type", ImageTypes, default=ImageTypes.GAUSS)
# LabeledEnum examples - Pattern 1 with invariant keys and UI labels
filter_method = gds.ChoiceItem(
"Filtering method", FilteringMethod, default=FilteringMethod.GAUSSIAN
)
threshold_mode = gds.ChoiceItem(
"Threshold mode", ThresholdMode, default=ThresholdMode.OTSU
)
mchoice2 = gds.ImageChoiceItem(
"Single choice 2",
[
("rect", "first choice", "gif.png"),
("ell", "second choice", "txt.png"),
("qcq", "third choice", "file.png"),
],
)
_eg = gds.EndGroup("A sub group")
floatarray = gds.FloatArrayItem(
"Float array", default=np.ones((50, 5), float), format=" %.2e "
).set_pos(col=1)
mchoice3 = gds.MultipleChoiceItem(
"MC type 1", [str(i) for i in range(12)]
).horizontal(4)
mchoice1 = (
gds.MultipleChoiceItem(
"MC type 2", ["first choice", "second choice", "third choice"]
)
.vertical(1)
.set_pos(col=1)
)
dictionary = gds.DictItem(
"Dictionary",
default={
"lkl": 2,
"tototo": 3,
"zzzz": "lklk",
"bool": True,
"float": 1.234,
"list": [1, 2.5, 3, "str", False, 5, {"lkl": 2, "l": [1, 2, 3]}],
},
help="This is a dictionary",
)
def test_all_items():
"""Test all DataItem objects"""
with qt_app_context():
prm = Parameters()
prm.floatarray[:, 0] = np.linspace(-5, 5, 50)
# Demonstrate LabeledEnum functionality
execenv.print("=== LabeledEnum Pattern 1 Demo ===")
execenv.print(f"Filter method (enum member): {prm.filter_method!r}")
execenv.print(f"Filter value (invariant key): {prm.filter_method.value!r}")
execenv.print(f"Filter label (UI display): {prm.filter_method.label!r}")
execenv.print(f"Filter str(): {str(prm.filter_method)!r}")
# Show different ways to set LabeledEnum values
prm.filter_method = "sobel" # Set by invariant key
execenv.print(f"Set by key 'sobel': {prm.filter_method!r}")
prm.filter_method = _("Median filter") # Set by UI label
execenv.print(f"Set by label 'Median filter': {prm.filter_method!r}")
prm.filter_method = 0 # Set by index
execenv.print(f"Set by index 0: {prm.filter_method!r}")
execenv.print("=== End LabeledEnum Demo ===")
execenv.print(prm)
if prm.edit():
execenv.print(prm)
prm.view()
execenv.print("OK")
if __name__ == "__main__":
test_all_items()
Embedding guidata objects in GUI layouts¶
import numpy as np
from qtpy.QtWidgets import QMainWindow, QSplitter
import guidata.dataset as gds
from guidata.configtools import get_icon
from guidata.dataset.qtwidgets import DataSetEditGroupBox, DataSetShowGroupBox
from guidata.env import execenv
from guidata.qthelpers import (
add_actions,
create_action,
get_std_icon,
qt_app_context,
win32_fix_title_bar_background,
)
from guidata.tests.dataset.test_activable_dataset import Parameters
from guidata.widgets import about
class AnotherDataSet(gds.DataSet):
"""
Example 2
<b>Simple dataset example</b>
"""
param0 = gds.ChoiceItem("Choice", ["deazdazk", "aeazee", "87575757"])
param1 = gds.FloatItem("Foobar 1", default=0, min=0)
a_group = gds.BeginGroup("A group")
param2 = gds.FloatItem("Foobar 2", default=0.93)
param3 = gds.FloatItem("Foobar 3", default=123)
_a_group = gds.EndGroup("A group")
class ExampleMultiGroupDataSet(gds.DataSet):
"""Example DS with multiple groups"""
choices = gds.MultipleChoiceItem("Choices", ["a", "b", "c", "d", "e"])
dictionary = gds.DictItem("Dictionary", {"a": 1, "b": 2, "c": 3})
param0 = gds.ChoiceItem("Choice", ["deazdazk", "aeazee", "87575757"])
param1 = gds.FloatItem("Foobar 1", default=0, min=0)
t_group = gds.BeginTabGroup("T group")
a_group = gds.BeginGroup("A group")
param2 = gds.FloatItem("Foobar 2", default=0.93)
dir1 = gds.DirectoryItem("Directory 1")
file1 = gds.FileOpenItem("File 1")
_a_group = gds.EndGroup("A group")
b_group = gds.BeginGroup("B group")
param3 = gds.FloatItem("Foobar 3", default=123)
param4 = gds.BoolItem("Boolean")
_b_group = gds.EndGroup("B group")
c_group = gds.BeginGroup("C group")
param5 = gds.FloatItem("Foobar 4", default=250)
param6 = gds.DateItem("Date").set_prop("display", format="dd.MM.yyyy")
param7 = gds.ColorItem("Color")
_c_group = gds.EndGroup("C group")
_t_group = gds.EndTabGroup("T group")
class OtherDataSet(gds.DataSet):
"""Another example dataset"""
group1 = gds.BeginGroup("Group 1")
title = gds.StringItem("Title", default="Title")
icon = gds.ChoiceItem(
"Icon",
(
("python.png", "Python"),
("guidata.svg", "guidata"),
("settings.png", "Settings"),
),
)
opacity = gds.FloatItem("Opacity", default=1.0, min=0.1, max=1)
transform = gds.FloatArrayItem("Transform", default=np.array([1, 2, 3, 4, 5, 6]))
_group1 = gds.EndGroup("Group 1")
group2 = gds.BeginGroup("Group 2")
computed = gds.StringItem("Computed").set_computed(
lambda ds: f"T: {ds.title}, I: {ds.icon}, O: {ds.opacity}"
)
_group2 = gds.EndGroup("Group 2")
class MainWindow(QMainWindow):
"""Main window"""
def __init__(self):
QMainWindow.__init__(self)
win32_fix_title_bar_background(self)
self.setWindowIcon(get_icon("python.png"))
self.setWindowTitle("Application example")
# Instantiate dataset-related widgets:
self.groupbox1 = DataSetShowGroupBox(
"Activable dataset", Parameters, comment=""
)
self.groupbox2 = DataSetShowGroupBox(
"Standard dataset", AnotherDataSet, comment=""
)
self.groupbox3 = DataSetEditGroupBox(
"Standard dataset", OtherDataSet, comment=""
)
self.groupbox4 = DataSetEditGroupBox(
"Standard dataset", ExampleMultiGroupDataSet, comment=""
)
self.groupbox3.SIG_APPLY_BUTTON_CLICKED.connect(self.update_window)
self.update_groupboxes()
splitter = QSplitter(self)
splitter.addWidget(self.groupbox1)
splitter.addWidget(self.groupbox2)
splitter.addWidget(self.groupbox3)
splitter.addWidget(self.groupbox4)
self.setCentralWidget(splitter)
self.setContentsMargins(10, 5, 10, 5)
# File menu
file_menu = self.menuBar().addMenu("File")
quit_action = create_action(
self,
"Quit",
shortcut="Ctrl+Q",
icon=get_std_icon("DialogCloseButton"),
tip="Quit application",
triggered=self.close,
)
add_actions(file_menu, (quit_action,))
# Edit menu
edit_menu = self.menuBar().addMenu("Edit")
editparam1_action = create_action(
self, "Edit dataset 1", triggered=self.edit_dataset1
)
editparam2_action = create_action(
self, "Edit dataset 2", triggered=self.edit_dataset2
)
editparam4_action = create_action(
self, "Edit dataset 4", triggered=self.edit_dataset4
)
ro_param4_action = create_action(
self, "Dataset 4: read-only", toggled=self.ro_dataset4
)
add_actions(
edit_menu,
(editparam1_action, editparam2_action, editparam4_action, ro_param4_action),
)
# ? menu
help_menu = self.menuBar().addMenu("?")
about_action = create_action(
self,
"About guidata",
icon=get_std_icon("MessageBoxInformation"),
triggered=about.show_about_dialog,
)
add_actions(help_menu, (about_action,))
def update_window(self):
"""Update window"""
dataset = self.groupbox3.dataset
self.setWindowTitle(dataset.title)
self.setWindowIcon(get_icon(dataset.icon))
self.setWindowOpacity(dataset.opacity)
def update_groupboxes(self):
"""Update groupboxes"""
self.groupbox1.dataset.set_activable(False) # This is an activable dataset
self.groupbox1.get()
self.groupbox2.get()
self.groupbox4.get()
def ro_dataset4(self, readonly: bool):
self.groupbox4.dataset.set_readonly(readonly)
self.groupbox4.get()
def edit_dataset1(self):
"""Edit dataset 1"""
self.groupbox1.dataset.set_activable(True) # This is an activable dataset
if self.groupbox1.dataset.edit(self):
self.update_groupboxes()
def edit_dataset2(self):
"""Edit dataset 2"""
if self.groupbox2.dataset.edit(self):
self.update_groupboxes()
def edit_dataset4(self):
"""Edit dataset 4"""
if self.groupbox4.dataset.edit(self):
self.update_groupboxes()
def test_editgroupbox():
"""Test editgroupbox"""
with qt_app_context(exec_loop=True):
window = MainWindow()
window.show()
execenv.print("OK")
if __name__ == "__main__":
test_editgroupbox()
Local automatic sliders¶
An embedded DataSetEditLayout can opt into sliders without changing shared
DataItem declarations or other forms:
editor = DataSetEditLayout(
parent, parameters, grid, change_callback=parameters_changed,
auto_sliders=True, slider_steps=1000,
)
The policy is inherited by nested groups and tabs. Editable numeric items need
finite, ordered, representable bounds; otherwise they remain text-only. Integer
parity is respected, and ranges crossing zero for nonzero items are not
automatically given sliders. For floats, a usable positive step is used when
practical, otherwise slider_steps specifies the normalized resolution. The
text field retains its exact value independently of the slider thumb.
slider=True retains its existing behavior. Set
item.set_prop("display", auto_slider=False) to exclude an item from the local
automatic policy. No bounds are inferred. The optional layout callback
slider_callback(pressed) receives True at drag start and False at
release; value changes still use the existing change_callback. Neither
callback automatically validates, accepts or applies the form. Use
check_all_values() before accept_changes() when collecting a draft.
Histogram-backed interval selection¶
HistogramRangeItem edits two distinct FloatItem fields in the same dataset.
Its default presentation is a generic interval, suitable for measurements such as
durations. The caller supplies histogram counts and range proposals; guidata does
not inspect source arrays or choose an automatic range.
The following tested dataset has bounded durations in seconds and a live dependent
field. Import guidata.dataset as gds before using it:
class DurationRange(gds.DataSet):
"""Select a duration interval from a caller-supplied histogram."""
minimum = gds.FloatItem(
"Minimum", default=0.0, min=0.0, max=10.0, unit="s"
).set_prop("display", hide=True)
maximum = gds.FloatItem(
"Maximum", default=10.0, min=0.0, max=10.0, unit="s"
).set_prop("display", hide=True)
width = gds.FloatItem("Selected duration", default=10.0, unit="s").set_prop(
"display", readonly=True
)
def update_width(self, item, value):
"""Refresh the dependent field from the complete edited pair."""
self.width = self.maximum - self.minimum
histogram = gds.HistogramRangeItem(
"Durations",
"minimum",
"maximum",
default={
"counts": [1, 4, 3, 2],
"domain": [0.0, 10.0],
"minimum_width": 0.01,
"active": True,
"auto_range": [2.0, 8.0],
"reset_range": [0.0, 10.0],
},
).set_prop("display", callback=update_width)
Call DurationRange().edit() to display it. The hidden numeric fields retain
their constraints, including nonzero and the check=False opt-out. A window
outside those constraints stays visible but cannot be accepted. The histogram’s
domain is only a drawing/slider domain, not an additional numeric constraint.
If either linked field is read-only or inactive, the entire composite is disabled.
The histogram payload is transient: only the linked numeric values are serialized. After loading a dataset, restore its histogram context before enabling editing. An empty context leaves the saved bounds visible and the controls disabled. Auto and Reset appear only when the caller supplies finite ordered proposals.
The callback receives (instance, item, payload) once per valid changed pair.
Both bounds are already on the working dataset, and dependent fields are refreshed.
Without callbacks or computed fields, edits remain local until acceptance. With
live dependencies, guidata updates the working dataset before acceptance, just as
for ordinary items. Applications requiring transactional Cancel must edit a copy;
the dialog cannot undo arbitrary callback side effects.
For image applications, explicitly select the brightness/contrast presentation:
DurationRange.histogram.set_prop("display", presentation="brightness_contrast")
This adds brightness/contrast controls and a linear transfer overlay. It changes
only rendering metadata, never the stored parameters. The JSON Schema exporter
emits x-guidata-histogram-presentation so portable renderers use the same mode.
Data item groups and group selection¶
import guidata.dataset as gds
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
prop1 = gds.ValueProp(False)
prop2 = gds.ValueProp(False)
class Parameters(gds.DataSet):
"""
Group selection test
<b>Group selection example:</b>
"""
g1 = gds.BeginGroup("group 1")
enable1 = gds.BoolItem(
"Enable parameter set #1",
help="If disabled, the following parameters will be ignored",
default=False,
).set_prop("display", store=prop1)
prm11 = gds.FloatItem("Prm 1.1", default=0, min=0).set_prop("display", active=prop1)
prm12 = gds.FloatItem("Prm 1.2", default=0.93).set_prop("display", active=prop1)
_g1 = gds.EndGroup("group 1")
g2 = gds.BeginGroup("group 2")
enable2 = gds.BoolItem(
"Enable parameter set #2",
help="If disabled, the following parameters will be ignored",
default=True,
).set_prop("display", store=prop2)
prm21 = gds.FloatItem("Prm 2.1", default=0, min=0).set_prop("display", active=prop2)
prm22 = gds.FloatItem("Prm 2.2", default=0.93).set_prop("display", active=prop2)
_g2 = gds.EndGroup("group 2")
def test_bool_selector():
"""Test bool selector"""
with qt_app_context():
prm = Parameters()
prm.edit()
execenv.print(prm)
execenv.print("OK")
if __name__ == "__main__":
test_bool_selector()
Activable data sets¶
class Parameters(gds.ActivableDataSet):
"""
Example
<b>Activable dataset example</b>
"""
def __init__(self, title=None, comment=None, icon=""):
gds.ActivableDataSet.__init__(self, title, comment, icon)
enable = gds.BoolItem(
"Enable parameter set",
help="If disabled, the following parameters will be ignored",
default=False,
)
param0 = gds.ChoiceItem("Param 0", ["choice #1", "choice #2", "choice #3"])
param1 = gds.FloatItem("Param 1", default=0, min=0)
param2 = gds.FloatItem("Param 2", default=0.93)
color = gds.ColorItem("Color", default="red")
Parameters.active_setup()
def test_activable_dataset():
"""Test activable dataset"""
with qt_app_context():
prm = Parameters()
prm.set_activable(True)
prm.edit()
prm.set_activable(False)
prm.edit()
prm.set_readonly()
prm.edit()
prm.set_readonly(False)
prm.edit()
execenv.print("OK")
if __name__ == "__main__":
test_activable_dataset()
Data set groups¶
from guidata.dataset import DataSetGroup
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_features import Parameters
def test_dataset_group():
"""Test DataSetGroup"""
with qt_app_context():
e1 = Parameters("DataSet #1")
e2 = Parameters("DataSet #2")
g = DataSetGroup([e1, e2], title="Parameters group")
g.edit()
execenv.print(e1)
g.edit()
execenv.print("OK")
g = DataSetGroup([e1, e2], title="Parameters group in table mode")
g.edit(mode="table")
execenv.print(e1)
g.edit()
execenv.print("OK")
g.edit()
execenv.print(e1)
g.edit()
execenv.print("OK")
if __name__ == "__main__":
test_dataset_group()
Utilities¶
Update/restore a dataset from/to a dictionary¶
import numpy as np
from guidata.dataset.conv import restore_dataset, update_dataset
from guidata.tests.dataset.test_all_items import Parameters
def test_update_restore_dataset():
"""Test update/restore dataset from/to another dataset or dictionary"""
dataset = Parameters()
dsdict = {
"integer": 1,
"float_slider": 1.0,
"bool1": True,
"string": "test",
"floatarray": np.array([1, 2, 3]),
"dictionary": {"a": 1, "b": 2},
}
# Update dataset from dictionary
update_dataset(dataset, dsdict)
# Check dataset values
assert dataset.integer == dsdict["integer"]
assert dataset.float_slider == dsdict["float_slider"]
assert dataset.bool1 == dsdict["bool1"]
assert dataset.string == dsdict["string"]
assert np.all(dataset.floatarray == dsdict["floatarray"])
assert dataset.dictionary == dsdict["dictionary"]
# Update dataset from another dataset
dataset2 = Parameters()
update_dataset(dataset2, dataset)
# Check dataset values
assert dataset2.integer == dataset.integer
assert dataset2.float_slider == dataset.float_slider
assert dataset2.bool1 == dataset.bool1
assert dataset2.string == dataset.string
assert np.all(dataset2.floatarray == dataset.floatarray)
assert dataset2.dictionary == dataset.dictionary
# Restore dataset from dictionary
restore_dataset(dataset, dsdict)
# Check dataset values
assert dataset.integer == dsdict["integer"]
assert dataset.float_slider == dsdict["float_slider"]
assert dataset.bool1 == dsdict["bool1"]
assert dataset.string == dsdict["string"]
assert np.all(dataset.floatarray == dsdict["floatarray"])
assert dataset.dictionary == dsdict["dictionary"]
if __name__ == "__main__":
test_update_restore_dataset()
Create a dataset class from a function signature¶
from __future__ import annotations
import numpy as np
from guidata.dataset import create_dataset_from_func
from guidata.env import execenv
def func_ok(
a: int, b: float, c: str = "test", d: dict[str, int] = {"x": 1, "y": 3}
) -> None:
"""A function with type annotations"""
pass
def func_no_type(a, b, c="test"):
"""A function without type annotations"""
pass
def func_no_default(a: int, b: float, c: str, data: np.ndarray) -> None:
"""A function without default values"""
pass
def test_dataset_from_func():
"""Test generate dataset class from function"""
for func in (func_ok, func_no_default):
execenv.print(func.__name__)
dataset = create_dataset_from_func(func)
execenv.print(dataset)
execenv.print(dataset.create(a=1, b=2.0))
execenv.print("")
func = func_no_type
try:
create_dataset_from_func(func)
assert False, "Should have raised a ValueError"
except ValueError:
# This is expected
pass
if __name__ == "__main__":
test_dataset_from_func()
Create a dataset class from a function dictionary¶
import numpy as np
from guidata.dataset import create_dataset_from_dict
from guidata.env import execenv
TEST_DICT1 = {
"a": 1,
"b": 2.0,
"c": "test",
"d": {"x": 1, "y": 3},
"data": np.array([1, 2, 3]),
}
TEST_DICT2 = {
"a": 1,
"unsupported": [2.0, 3.0],
}
def test_dataset_from_dict():
"""Test generate dataset class from a dictionary"""
for dictionary in (TEST_DICT1,):
execenv.print(dictionary)
dataset = create_dataset_from_dict(dictionary)
execenv.print(dataset)
execenv.print(dataset.create())
execenv.print("")
try:
create_dataset_from_dict(TEST_DICT2)
assert False, "Should have raised a ValueError"
except ValueError:
# This is expected
pass
if __name__ == "__main__":
test_dataset_from_dict()
Data set HDF5 serialization/deserialization¶
import os.path as osp
import tempfile
from guidata.dataset import assert_datasets_equal
from guidata.env import execenv
from guidata.io import HDF5Reader, HDF5Writer
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_items import Parameters
def test_loadsave_hdf5():
"""Test HDF5 I/O"""
with tempfile.TemporaryDirectory() as temp_dir:
fname = osp.join(temp_dir, "test.h5")
with qt_app_context():
p1 = Parameters()
# p1.edit()
# Save to HDF5 file
writer = HDF5Writer(fname)
p1.serialize(writer)
writer.close()
p2 = Parameters()
# Set all items to None for testing purposes:
for item in p2._items:
item.__set__(p2, None)
# Load from HDF5 file
reader = HDF5Reader(fname)
p2.deserialize(reader)
reader.close()
assert_datasets_equal(p1, p2, "Parameters do not match after HDF5 I/O")
execenv.print("OK")
if __name__ == "__main__":
test_loadsave_hdf5()
Data set JSON serialization/deserialization¶
import os
import guidata.dataset as gds
from guidata.env import execenv
from guidata.io import JSONReader, JSONWriter
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_items import Parameters
def test_loadsave_json():
"""Test JSON I/O"""
fname = "test.json"
with qt_app_context():
if os.path.exists(fname):
os.unlink(fname)
p1 = Parameters()
if execenv.unattended or p1.edit():
writer = JSONWriter(fname)
p1.serialize(writer)
writer.save()
p2 = Parameters()
reader = JSONReader(fname)
p2.deserialize(reader)
reader.close()
p2.edit()
os.unlink(fname)
# TODO: Uncomment this part of the test, and make it work!
# if execenv.unattended:
# assert_datasets_equal(p1, p2, "Parameters do not match after HDF5 I/O")
execenv.print("OK")
def test_transient_item_is_not_serialized():
"""Transient items are skipped by JSON serialization and deserialization."""
class ParametersWithTransientItem(gds.DataSet):
"""Dataset holding a transient rendering payload beside persisted bounds."""
minimum = gds.FloatItem("Minimum", default=0.0)
maximum = gds.FloatItem("Maximum", default=1.0)
histogram = gds.HistogramRangeItem(
"Brightness and contrast", "minimum", "maximum"
)
source = ParametersWithTransientItem()
source.minimum = 0.25
source.maximum = 0.75
source.histogram = {"counts": [1, 2, 3]}
restored = gds.json_to_dataset(
gds.dataset_to_json(source),
strict=True,
expected_class=ParametersWithTransientItem,
)
assert restored.minimum == 0.25
assert restored.maximum == 0.75
assert restored.histogram == {}
if __name__ == "__main__":
test_loadsave_json()