diff --git a/geoh5py/data/__init__.py b/geoh5py/data/__init__.py
index e369bcac2..db5272bd8 100644
--- a/geoh5py/data/__init__.py
+++ b/geoh5py/data/__init__.py
@@ -86,3 +86,18 @@ def from_primitive_type(cls, primitive_type: PrimitiveTypeEnum) -> type:
:return: The data type.
"""
return DataTypeEnum[primitive_type.name].value
+
+ @classmethod
+ def _missing_(cls, value) -> DataTypeEnum:
+ """
+ Allows for case-insensitive matching of enum members.
+
+ For example, "Integer" will match "INTEGER".
+
+ :param value: The value to match against the enum members.
+ """
+ if isinstance(value, str):
+ normalized = value.upper()
+ if normalized in cls.__members__:
+ return cls[normalized]
+ return super()._missing_(value)
diff --git a/geoh5py/data/data_association_enum.py b/geoh5py/data/data_association_enum.py
index 84e0987c0..1cbec080d 100644
--- a/geoh5py/data/data_association_enum.py
+++ b/geoh5py/data/data_association_enum.py
@@ -37,3 +37,18 @@ class DataAssociationEnum(Enum):
FACE = 4
GROUP = 5
DEPTH = 6
+
+ @classmethod
+ def _missing_(cls, value) -> DataAssociationEnum:
+ """
+ Allows for case-insensitive matching of enum members.
+
+ For example, "Cell" will match "CELL".
+
+ :param value: The value to match against the enum members.
+ """
+ if isinstance(value, str):
+ normalized = value.upper()
+ if normalized in cls.__members__:
+ return cls[normalized]
+ return super()._missing_(value)
diff --git a/geoh5py/shared/utils.py b/geoh5py/shared/utils.py
index cec533ea6..1310342b0 100644
--- a/geoh5py/shared/utils.py
+++ b/geoh5py/shared/utils.py
@@ -39,6 +39,8 @@
from .exceptions import Geoh5FileClosedError
+UidOrNumeric = UUID | float | int | None
+StringOrNumeric = str | float | int
# pylint: disable=too-many-lines
if TYPE_CHECKING:
@@ -1439,3 +1441,14 @@ def map_to_class(
class_map[identifier] = member
return class_map
+
+
+def enum_name_to_str(value: Enum) -> str:
+ """
+ Convert enum name to capitalized string.
+
+ :param value: Enum value to convert.
+
+ :return: Capitalized string.
+ """
+ return value.name.capitalize()
diff --git a/geoh5py/shared/validators.py b/geoh5py/shared/validators.py
index 0cd7ecdb0..7efe98e2f 100644
--- a/geoh5py/shared/validators.py
+++ b/geoh5py/shared/validators.py
@@ -145,13 +145,6 @@ def to_class(
return out
-def none_to_empty_string(value):
- """None transforms to empty string for serialization."""
- if value is None:
- return ""
- return value
-
-
def types_to_string(types: list) -> list[str] | str:
if len(types) > 1:
return [f"{{{k.default_type_uid()!s}}}" for k in types]
diff --git a/geoh5py/ui_json/annotations.py b/geoh5py/ui_json/annotations.py
index 33f9c982e..9de8c97b0 100644
--- a/geoh5py/ui_json/annotations.py
+++ b/geoh5py/ui_json/annotations.py
@@ -18,27 +18,28 @@
# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
import logging
+from pathlib import Path
from typing import Annotated, Any
from uuid import UUID
from pydantic import BeforeValidator, Field, PlainSerializer
-from geoh5py.ui_json.validations.form import empty_string_to_none, uuid_to_string
+from geoh5py.data import DataAssociationEnum, DataTypeEnum
+from geoh5py.groups import Group
+from geoh5py.objects import ObjectBase
+from geoh5py.shared.utils import enum_name_to_str, stringify
+from geoh5py.shared.validators import (
+ to_class,
+ to_list,
+ to_path,
+ to_type_uid_or_class,
+ types_to_string,
+)
+from geoh5py.ui_json.utils import optional_uuid_mapper
logger = logging.getLogger(__name__)
-OptionalUUIDList = Annotated[
- list[UUID] | None, # pylint: disable=unsupported-binary-operation
- BeforeValidator(empty_string_to_none),
- PlainSerializer(uuid_to_string),
-]
-
-OptionalValueList = Annotated[
- float | list[float] | None,
- BeforeValidator(empty_string_to_none),
-]
-
def deprecate(value, info):
"""Issue deprecation warning."""
@@ -46,8 +47,58 @@ def deprecate(value, info):
return value
+AssociationOptions = Annotated[
+ DataAssociationEnum,
+ PlainSerializer(enum_name_to_str),
+]
+
+DataTypeOptions = Annotated[
+ DataTypeEnum,
+ PlainSerializer(enum_name_to_str),
+]
+
+
Deprecated = Annotated[
Any,
Field(exclude=True),
BeforeValidator(deprecate),
]
+
+GroupTypes = Annotated[
+ list[type[Group]],
+ BeforeValidator(to_class),
+ BeforeValidator(to_type_uid_or_class),
+ BeforeValidator(to_list),
+ PlainSerializer(types_to_string, when_used="json"),
+]
+
+MeshTypes = Annotated[
+ list[type[ObjectBase]],
+ BeforeValidator(to_class),
+ BeforeValidator(to_type_uid_or_class),
+ BeforeValidator(to_list),
+ PlainSerializer(types_to_string, when_used="json"),
+]
+
+OptionalUUID = Annotated[
+ UUID | None,
+ BeforeValidator(optional_uuid_mapper),
+ PlainSerializer(stringify),
+]
+
+OptionalUUIDList = Annotated[
+ list[UUID] | None,
+ BeforeValidator(optional_uuid_mapper),
+ PlainSerializer(stringify),
+]
+
+OptionalValueList = Annotated[
+ float | list[float] | None,
+ BeforeValidator(optional_uuid_mapper),
+]
+
+PathList = Annotated[
+ list[Path],
+ BeforeValidator(to_path),
+ BeforeValidator(to_list),
+]
diff --git a/geoh5py/ui_json/forms.py b/geoh5py/ui_json/forms.py
index a0b327c32..6897b3f66 100644
--- a/geoh5py/ui_json/forms.py
+++ b/geoh5py/ui_json/forms.py
@@ -22,14 +22,13 @@
from enum import Enum
from pathlib import Path
-from typing import Annotated, Any
+from typing import Any
from uuid import UUID
import numpy as np
from pydantic import (
BaseModel,
ConfigDict,
- PlainSerializer,
TypeAdapter,
ValidationError,
field_serializer,
@@ -37,23 +36,17 @@
model_validator,
)
from pydantic.alias_generators import to_camel, to_snake
-from pydantic.functional_validators import BeforeValidator
-
-from geoh5py.data import DataAssociationEnum, DataTypeEnum
-from geoh5py.groups import Group, GroupTypeEnum
-from geoh5py.objects import ObjectBase
-from geoh5py.shared.validators import (
- to_class,
- to_list,
- to_path,
- to_type_uid_or_class,
- types_to_string,
-)
-from geoh5py.ui_json.annotations import OptionalUUIDList, OptionalValueList
-from geoh5py.ui_json.validations.form import (
- empty_string_to_none,
- uuid_to_string,
- uuid_to_string_or_numeric,
+
+from geoh5py.groups import GroupTypeEnum
+from geoh5py.ui_json.annotations import (
+ AssociationOptions,
+ DataTypeOptions,
+ GroupTypes,
+ MeshTypes,
+ OptionalUUID,
+ OptionalUUIDList,
+ OptionalValueList,
+ PathList,
)
@@ -304,13 +297,6 @@ def valid_choice(self):
return self
-PathList = Annotated[
- list[Path],
- BeforeValidator(to_path),
- BeforeValidator(to_list),
-]
-
-
class FileForm(BaseForm):
"""
File path uijson form.
@@ -428,21 +414,6 @@ def force_file_description(cls, _):
return ["Directory"]
-MeshTypes = Annotated[
- list[type[ObjectBase]],
- BeforeValidator(to_class),
- BeforeValidator(to_type_uid_or_class),
- BeforeValidator(to_list),
- PlainSerializer(types_to_string, when_used="json"),
-]
-
-OptionalUUID = Annotated[
- UUID | None, # pylint: disable=unsupported-binary-operation
- BeforeValidator(empty_string_to_none),
- PlainSerializer(uuid_to_string),
-]
-
-
class ObjectForm(BaseForm):
"""
Geoh5py object uijson form.
@@ -457,15 +428,6 @@ class ObjectForm(BaseForm):
mesh_type: MeshTypes
-GroupTypes = Annotated[
- list[type[Group]],
- BeforeValidator(to_class),
- BeforeValidator(to_type_uid_or_class),
- BeforeValidator(to_list),
- PlainSerializer(types_to_string, when_used="json"),
-]
-
-
class GroupForm(BaseForm):
"""
Geoh5py group uijson form.
@@ -480,23 +442,6 @@ class GroupForm(BaseForm):
group_type: GroupTypes
-Association = Enum( # type: ignore
- "Association",
- [(k.name, k.name.capitalize()) for k in DataAssociationEnum],
- type=str,
-)
-
-DataType = Enum( # type: ignore
- "DataType", [(k.name, k.name.capitalize()) for k in DataTypeEnum], type=str
-)
-
-UUIDOrNumber = Annotated[
- UUID | float | int | None, # pylint: disable=unsupported-binary-operation
- BeforeValidator(empty_string_to_none),
- PlainSerializer(uuid_to_string_or_numeric),
-]
-
-
class DataFormMixin(BaseModel):
"""
Mixin class to add common attributes a series of data classes.
@@ -513,8 +458,8 @@ class DataFormMixin(BaseModel):
"""
parent: str
- association: Association | list[Association]
- data_type: DataType | list[DataType]
+ association: AssociationOptions | list[AssociationOptions]
+ data_type: DataTypeOptions | list[DataTypeOptions]
class DataForm(DataFormMixin, BaseForm):
@@ -562,7 +507,7 @@ class GroupMultiDataForm(BaseForm):
group_type: GroupTypes
group_value: OptionalUUID
- data_type: DataType | list[DataType]
+ data_type: DataTypeOptions | list[DataTypeOptions]
value: str | list[str]
multi_select: bool = True
diff --git a/geoh5py/ui_json/ui_json.py b/geoh5py/ui_json/ui_json.py
index 30a4fdf89..17dc3bfd7 100644
--- a/geoh5py/ui_json/ui_json.py
+++ b/geoh5py/ui_json/ui_json.py
@@ -38,19 +38,23 @@
from geoh5py import Workspace
from geoh5py.groups import PropertyGroup, UIJsonGroup
from geoh5py.shared import Entity
-from geoh5py.shared.utils import fetch_active_workspace, str2uuid, stringify
-from geoh5py.shared.validators import none_to_empty_string
+from geoh5py.shared.utils import (
+ fetch_active_workspace,
+ none2str,
+ str2none,
+ str2uuid,
+ stringify,
+)
from geoh5py.ui_json.forms import BaseForm
-from geoh5py.ui_json.validations import ErrorPool, UIJsonError, get_validations
-from geoh5py.ui_json.validations.form import empty_string_to_none
+from geoh5py.ui_json.validation import ErrorPool, UIJsonError, get_validations
logger = logging.getLogger(__name__)
OptionalPath = Annotated[
- Path | None, # pylint: disable=unsupported-binary-operation
- BeforeValidator(empty_string_to_none),
- PlainSerializer(none_to_empty_string),
+ Path | None,
+ BeforeValidator(str2none),
+ PlainSerializer(none2str),
]
diff --git a/geoh5py/ui_json/utils.py b/geoh5py/ui_json/utils.py
index e6c4b601a..64d24fe3a 100644
--- a/geoh5py/ui_json/utils.py
+++ b/geoh5py/ui_json/utils.py
@@ -31,7 +31,12 @@
from geoh5py import Workspace
from geoh5py.groups import ContainerGroup, Group
from geoh5py.objects import ObjectBase
-from geoh5py.shared.utils import fetch_active_workspace
+from geoh5py.shared.utils import (
+ dict_mapper,
+ entity2uuid,
+ fetch_active_workspace,
+ str2none,
+)
logger = getLogger(__name__)
@@ -531,3 +536,13 @@ def monitored_directory_copy(
move(working_path / temp_geoh5, directory_path / temp_geoh5, copy)
return str(directory_path / temp_geoh5)
+
+
+def optional_uuid_mapper(value: Any):
+ """
+ Take values and convert them into UUID or None (or list of).
+
+ :param value: Either a string of entity, or list of.
+ :return: UUID, Nont or list of.
+ """
+ return dict_mapper(value, [str2none, entity2uuid])
diff --git a/geoh5py/ui_json/validation.py b/geoh5py/ui_json/validation.py
index b971df522..956579528 100644
--- a/geoh5py/ui_json/validation.py
+++ b/geoh5py/ui_json/validation.py
@@ -20,12 +20,15 @@
from __future__ import annotations
+from collections.abc import Callable
from copy import deepcopy
from typing import Any, cast
from uuid import UUID
from warnings import warn
+from geoh5py.data import Data
from geoh5py.groups import PropertyGroup
+from geoh5py.objects import ObjectBase
from geoh5py.shared import Entity
from geoh5py.shared.exceptions import RequiredValidationError
from geoh5py.shared.validators import (
@@ -315,3 +318,114 @@ def __call__(self, data, *args):
"InputValidators can only be called with dictionary of data or "
"(key, value) pair."
)
+
+
+## Validation utility for UIJson class ##
+class UIJsonError(Exception):
+ """Exception raised for errors in the UIJson object."""
+
+ def __init__(self, message: str):
+ super().__init__(message)
+
+
+class ErrorPool: # pylint: disable=too-few-public-methods
+ """
+ Stores validation errors for all UIJson members.
+
+ :param errors: Dictionary mapping parameter names to lists of
+ exceptions encountered during validation.
+ """
+
+ def __init__(self, errors: dict[str, list[Exception]]):
+ self.pool = errors
+
+ def _format_error_message(self):
+ """Format the error message for the UIJsonError."""
+
+ msg = ""
+ for key, errors in self.pool.items():
+ if errors:
+ msg += f"\t{key}:\n"
+ for i, error in enumerate(errors):
+ msg += f"\t\t{i}. {error}\n"
+
+ return msg
+
+ def throw(self):
+ """Raise the UIJsonError with detailed list of errors per parameter."""
+
+ message = self._format_error_message()
+ if message:
+ message = "Collected UIJson errors:\n" + message
+ raise UIJsonError(message)
+
+
+def dependency_type_validation(
+ name: str, data: dict[str, Any], json_dict: dict[str, Any]
+):
+ """
+ Validate that the dependency for is optional or bool type.
+
+ :param name: Name of the form
+ :param data: Input data with known validations.
+ :param json_dict: A dict representation of the UIJson object.
+ """
+
+ dependency = json_dict[name]["dependency"]
+ dependency_form = json_dict[dependency]
+ if "optional" not in dependency_form and not isinstance(data[dependency], bool):
+ raise UIJsonError(
+ f"Dependency {dependency} must be either optional or of boolean type."
+ )
+
+
+def get_validations(form_keys: list[str]) -> list[Callable]:
+ """
+ Get callable validations based on identifying form keys.
+
+ :param form_keys: List of form keys.
+
+ :return: List of callable validations.
+ """
+ return [VALIDATIONS_MAP[k] for k in form_keys if k in VALIDATIONS_MAP]
+
+
+def mesh_type_validation(name: str, data: dict[str, Any], json_dict: dict[str, Any]):
+ """
+ Validate that value is one of the provided mesh types.
+
+ :param name: Name of the form
+ :param data: Input data with known validations.
+ :param json_dict: A dict representation of the UIJson object.
+ """
+
+ mesh_types = json_dict[name]["mesh_type"]
+ obj = data[name]
+ if not isinstance(obj, tuple(mesh_types)):
+ raise UIJsonError(f"Object's mesh type must be one of {mesh_types}.")
+
+
+def parent_validation(name: str, data: dict[str, Any], json_dict: dict[str, Any]):
+ """
+ Validate that the data is a child of the parent object.
+
+ :param name: Name of the form
+ :param data: Input data with known validations.
+ :param json_dict: A dict representation of the UIJson object.
+ """
+
+ form = json_dict[name]
+ child = data[name]
+ parent = data[form["parent"]]
+
+ if not isinstance(parent, ObjectBase) or (
+ isinstance(child, Data) and parent.get_entity(child.uid)[0] is None
+ ):
+ raise UIJsonError(f"{name} data is not a child of {form['parent']}.")
+
+
+VALIDATIONS_MAP = {
+ "dependency": dependency_type_validation,
+ "mesh_type": mesh_type_validation,
+ "parent": parent_validation,
+}
diff --git a/geoh5py/ui_json/validations/__init__.py b/geoh5py/ui_json/validations/__init__.py
deleted file mode 100644
index 315aea7c9..000000000
--- a/geoh5py/ui_json/validations/__init__.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-# Copyright (c) 2020-2026 Mira Geoscience Ltd. '
-# '
-# This file is part of geoh5py. '
-# '
-# geoh5py is free software: you can redistribute it and/or modify '
-# it under the terms of the GNU Lesser General Public License as published by '
-# the Free Software Foundation, either version 3 of the License, or '
-# (at your option) any later version. '
-# '
-# geoh5py is distributed in the hope that it will be useful, '
-# but WITHOUT ANY WARRANTY; without even the implied warranty of '
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '
-# GNU Lesser General Public License for more details. '
-# '
-# You should have received a copy of the GNU Lesser General Public License '
-# along with geoh5py. If not, see . '
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-from collections.abc import Callable
-
-from .uijson import (
- ErrorPool,
- UIJsonError,
- dependency_type_validation,
- mesh_type_validation,
- parent_validation,
-)
-
-
-VALIDATIONS_MAP = {
- "dependency": dependency_type_validation,
- "mesh_type": mesh_type_validation,
- "parent": parent_validation,
-}
-
-
-def get_validations(form_keys: list[str]) -> list[Callable]:
- """Returns a list of callable validations based on identifying form keys."""
- return [VALIDATIONS_MAP[k] for k in form_keys if k in VALIDATIONS_MAP]
diff --git a/geoh5py/ui_json/validations/form.py b/geoh5py/ui_json/validations/form.py
deleted file mode 100644
index 734ba3a6b..000000000
--- a/geoh5py/ui_json/validations/form.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-# Copyright (c) 2020-2026 Mira Geoscience Ltd. '
-# '
-# This file is part of geoh5py. '
-# '
-# geoh5py is free software: you can redistribute it and/or modify '
-# it under the terms of the GNU Lesser General Public License as published by '
-# the Free Software Foundation, either version 3 of the License, or '
-# (at your option) any later version. '
-# '
-# geoh5py is distributed in the hope that it will be useful, '
-# but WITHOUT ANY WARRANTY; without even the implied warranty of '
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '
-# GNU Lesser General Public License for more details. '
-# '
-# You should have received a copy of the GNU Lesser General Public License '
-# along with geoh5py. If not, see . '
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-from uuid import UUID
-
-
-UidOrNumeric = UUID | float | int | None
-StringOrNumeric = str | float | int
-
-
-def uuid_to_string(value: UUID | list[UUID] | None) -> str | list[str]:
- """Serialize UUID(s) as a string."""
-
- def convert(value: UUID | None) -> str:
- if value is None:
- return ""
- if isinstance(value, UUID):
- return f"{{{value!s}}}"
- return value
-
- if isinstance(value, list):
- return [convert(v) for v in value]
- return convert(value)
-
-
-def empty_string_to_none(value):
- """Promote empty string to uid, and pass all other values."""
- if value == "":
- return None
- return value
-
-
-def uuid_to_string_or_numeric(
- value: UidOrNumeric | list[UidOrNumeric],
-) -> StringOrNumeric | list[StringOrNumeric]:
- def convert(value: UidOrNumeric) -> StringOrNumeric:
- if value is None:
- return ""
- if isinstance(value, UUID):
- return f"{{{value}}}"
- return value
-
- if isinstance(value, list):
- return [convert(v) for v in value]
- return convert(value)
diff --git a/geoh5py/ui_json/validations/uijson.py b/geoh5py/ui_json/validations/uijson.py
deleted file mode 100644
index f0e61e927..000000000
--- a/geoh5py/ui_json/validations/uijson.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-# Copyright (c) 2020-2026 Mira Geoscience Ltd. '
-# '
-# This file is part of geoh5py. '
-# '
-# geoh5py is free software: you can redistribute it and/or modify '
-# it under the terms of the GNU Lesser General Public License as published by '
-# the Free Software Foundation, either version 3 of the License, or '
-# (at your option) any later version. '
-# '
-# geoh5py is distributed in the hope that it will be useful, '
-# but WITHOUT ANY WARRANTY; without even the implied warranty of '
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '
-# GNU Lesser General Public License for more details. '
-# '
-# You should have received a copy of the GNU Lesser General Public License '
-# along with geoh5py. If not, see . '
-# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-from typing import Any
-
-from geoh5py.data import Data
-from geoh5py.objects import ObjectBase
-
-
-class UIJsonError(Exception):
- """Exception raised for errors in the UIJson object."""
-
- def __init__(self, message: str):
- super().__init__(message)
-
-
-class ErrorPool: # pylint: disable=too-few-public-methods
- """Stores validation errors for all UIJson members."""
-
- def __init__(self, errors: dict[str, list[Exception]]):
- self.pool = errors
-
- def _format_error_message(self):
- """Format the error message for the UIJsonError."""
-
- msg = ""
- for key, errors in self.pool.items():
- if errors:
- msg += f"\t{key}:\n"
- for i, error in enumerate(errors):
- msg += f"\t\t{i}. {error}\n"
-
- return msg
-
- def throw(self):
- """Raise the UIJsonError with detailed list of errors per parameter."""
-
- message = self._format_error_message()
- if message:
- message = "Collected UIJson errors:\n" + message
- raise UIJsonError(message)
-
-
-def dependency_type_validation(name: str, data: dict[str, Any], params: dict[str, Any]):
- """Dependency is optional or bool type."""
-
- dependency = params[name]["dependency"]
- dependency_form = params[dependency]
- if "optional" not in dependency_form and not isinstance(data[dependency], bool):
- raise UIJsonError(
- f"Dependency {dependency} must be either optional or of boolean type."
- )
-
-
-def mesh_type_validation(name: str, data: dict[str, Any], params: dict[str, Any]):
- """Promoted value is one of the provided mesh types."""
-
- mesh_types = params[name]["mesh_type"]
- obj = data[name]
- if not isinstance(obj, tuple(mesh_types)):
- raise UIJsonError(f"Object's mesh type must be one of {mesh_types}.")
-
-
-def parent_validation(name: str, data: dict[str, Any], params: dict[str, Any]):
- """Data is a child of the parent object."""
-
- form = params[name]
- child = data[name]
- parent = data[form["parent"]]
-
- if not isinstance(parent, ObjectBase) or (
- isinstance(child, Data) and parent.get_entity(child.uid)[0] is None
- ):
- raise UIJsonError(f"{name} data is not a child of {form['parent']}.")
diff --git a/tests/ui_json/forms_test.py b/tests/ui_json/forms_test.py
index fae8010f7..b22384973 100644
--- a/tests/ui_json/forms_test.py
+++ b/tests/ui_json/forms_test.py
@@ -27,10 +27,10 @@
from pydantic import BaseModel, ValidationError
from geoh5py import Workspace
+from geoh5py.data import DataAssociationEnum, DataTypeEnum
from geoh5py.groups import GroupTypeEnum, PropertyGroup
from geoh5py.objects import Curve, DrapeModel, Points, Surface
from geoh5py.ui_json.forms import (
- Association,
BaseForm,
BoolForm,
ChoiceForm,
@@ -38,7 +38,6 @@
DataGroupForm,
DataOrValueForm,
DataRangeForm,
- DataType,
DirectoryForm,
FileForm,
FloatForm,
@@ -430,6 +429,10 @@ def test_object_form_mesh_type_as_classes(tmp_path):
assert isinstance(ws.get_entity(form.value)[0], tuple(form.mesh_type))
+ form_entity = ObjectForm(label="name", value=points, mesh_type=[Points])
+
+ assert form.value == form_entity.value
+
def test_object_form_empty_string_handling():
form = ObjectForm(label="name", value="", mesh_type=[Points, Surface])
@@ -448,8 +451,8 @@ def test_data_form():
assert form.label == "name"
assert form.value == uuid.UUID(data_uid)
assert form.parent == "my_param"
- assert form.association == "Vertex"
- assert form.data_type == "Float"
+ assert form.association.name == "VERTEX"
+ assert form.data_type.name == "FLOAT"
form = DataForm(
label="name",
@@ -458,8 +461,8 @@ def test_data_form():
association=["Vertex", "Cell"],
data_type=["Float", "Integer"],
)
- assert form.association == [Association.VERTEX, Association.CELL]
- assert form.data_type == [DataType.FLOAT, DataType.INTEGER]
+ assert form.association == [DataAssociationEnum.VERTEX, DataAssociationEnum.CELL]
+ assert form.data_type == [DataTypeEnum.FLOAT, DataTypeEnum.INTEGER]
def test_data_group_form():
@@ -476,8 +479,8 @@ def test_data_group_form():
assert form.value == uuid.UUID(group_uid)
assert form.data_group_type == GroupTypeEnum.STRIKEDIP
assert form.parent == "Da-da"
- assert form.association == [Association.VERTEX, Association.CELL]
- assert form.data_type == [DataType.FLOAT, DataType.INTEGER]
+ assert form.association == [DataAssociationEnum.VERTEX, DataAssociationEnum.CELL]
+ assert form.data_type == [DataTypeEnum.FLOAT, DataTypeEnum.INTEGER]
def test_data_or_value_form():
@@ -494,8 +497,8 @@ def test_data_or_value_form():
assert form.label == "name"
assert form.value == 0.0
assert form.parent == "my_param"
- assert form.association == "Vertex"
- assert form.data_type == "Float"
+ assert form.association.name == "VERTEX"
+ assert form.data_type.name == "FLOAT"
assert not form.is_value
assert form.property == uuid.UUID(data_uid)
@@ -528,8 +531,8 @@ def test_multichoice_data_form():
assert form.label == "name"
assert form.value == [uuid.UUID(data_uid_1)]
assert form.parent == "my_param"
- assert form.association == "Vertex"
- assert form.data_type == "Float"
+ assert form.association.name == "VERTEX"
+ assert form.data_type.name == "FLOAT"
form = MultiSelectDataForm(
label="name",
@@ -541,6 +544,26 @@ def test_multichoice_data_form():
)
assert form.value == [uuid.UUID(data_uid_1), uuid.UUID(data_uid_2)]
+ ws = Workspace()
+ obj = Points.create(ws, vertices=np.random.randn(100, 3))
+ data_list = obj.add_data(
+ {f"data{i}": {"values": np.random.randn(100)} for i in range(5)}
+ )
+
+ form = MultiSelectDataForm(
+ label="name",
+ value=data_list,
+ parent="my_param",
+ association="Vertex",
+ data_type="Float",
+ multi_select=True,
+ )
+
+ assert len(data_list) == len(form.value)
+ assert all(
+ data.uid == val for data, val in zip(data_list, form.value, strict=False)
+ )
+
def test_multichoice_data_form_serialization():
data_uid_1 = f"{{{uuid.uuid4()!s}}}"
@@ -597,8 +620,8 @@ def test_data_range_form():
assert form.property == uuid.UUID(data_uid)
assert form.value == [0.0, 1.0]
assert form.parent == "my_param"
- assert form.association == "Vertex"
- assert form.data_type == "Float"
+ assert form.association.name == "VERTEX"
+ assert form.data_type.name == "FLOAT"
assert form.range_label == "value range"
@@ -862,7 +885,7 @@ def test_multi_data_group_form():
assert form.label == "name"
assert form.value == [data_uid_1, data_uid_2]
assert form.group_value == uuid.UUID(group_uid)
- assert form.data_type == [DataType.FLOAT, DataType.INTEGER]
+ assert form.data_type == [DataTypeEnum.FLOAT, DataTypeEnum.INTEGER]
assert form.multi_select
assert form.tooltip == ["some ", "tooltip ", "text"]
diff --git a/tests/ui_json/uijson_test.py b/tests/ui_json/uijson_test.py
index 383e54a58..cd47c5ea9 100644
--- a/tests/ui_json/uijson_test.py
+++ b/tests/ui_json/uijson_test.py
@@ -43,7 +43,7 @@
StringForm,
)
from geoh5py.ui_json.ui_json import BaseUIJson
-from geoh5py.ui_json.validations import UIJsonError
+from geoh5py.ui_json.validation import UIJsonError
@pytest.fixture
@@ -547,6 +547,11 @@ def test_unknown_uijson(tmp_path):
assert "my_group_optional_parameter" not in params
assert "my_grouped_parameter" not in params
+ re_loaded = BaseUIJson.read(tmp_path / "test_copy.ui.json")
+
+ for name in uijson.model_fields_set:
+ assert getattr(re_loaded, name) == getattr(uijson, name)
+
def test_str_and_repr(tmp_path):
Workspace.create(tmp_path / "test.geoh5")