diff --git a/geoh5py/shared/exceptions.py b/geoh5py/shared/exceptions.py
index 70e51125a..cab77c5e5 100644
--- a/geoh5py/shared/exceptions.py
+++ b/geoh5py/shared/exceptions.py
@@ -56,31 +56,6 @@ def message(cls, name, err):
return f"Malformed ui.json dictionary for parameter '{name}'. {err}"
-class UIJsonFormatError(BaseValidationError):
- def __init__(self, name, msg):
- super().__init__(f"Invalid UIJson format for parameter '{name}'. {msg}")
-
- @classmethod
- def message(cls, name, value, validation):
- pass
-
-
-class AggregateValidationError(BaseValidationError):
- def __init__(
- self,
- name: str,
- value: list[BaseValidationError],
- ):
- super().__init__(AggregateValidationError.message(name, value))
-
- @classmethod
- def message(cls, name, value, validation=None):
- msg = f"\n\nValidation of '{name}' collected {len(value)} errors:\n"
- for i, err in enumerate(value):
- msg += f"\t{i}. {err!s}\n"
- return msg
-
-
class OptionalValidationError(BaseValidationError):
"""Error if None value provided to non-optional parameter."""
@@ -140,24 +115,6 @@ def message(cls, name, value, validation=None):
return f"Must provide at least one {name}. Options are: {opts}"
-class TypeUIDValidationError(BaseValidationError):
- """Error on type uid validation."""
-
- def __init__(self, name: str, value, validation: list[str]):
- super().__init__(
- TypeUIDValidationError.message(
- name, value.default_type_uid(), list(validation)
- )
- )
-
- @classmethod
- def message(cls, name, value, validation):
- return (
- f"Type uid '{value}' provided for '{name}' is invalid."
- + iterable_message(validation)
- )
-
-
class RequiredValidationError(BaseValidationError):
def __init__(self, name: str):
super().__init__(RequiredValidationError.message(name))
@@ -167,47 +124,6 @@ def message(cls, name, value=None, validation=None):
return f"Missing required parameter: '{name}'."
-class InCollectionValidationError(BaseValidationError):
- collection = "Collection"
- item = "data"
-
- def __init__(self, name: str, value: list[str]):
- super().__init__(self.message(name, value))
-
- @classmethod
- def message(cls, name, value, validation=None):
- _ = validation
- return f"{cls.collection}: '{name}' is missing required {cls.item}(s): {value}."
-
-
-class RequiredFormMemberValidationError(InCollectionValidationError):
- collection = "Form"
- item = "member"
-
-
-class RequiredUIJsonParameterValidationError(InCollectionValidationError):
- collection = "UIJson"
- item = "parameter"
-
-
-class RequiredWorkspaceObjectValidationError(InCollectionValidationError):
- collection = "Workspace"
- item = "object"
-
-
-class RequiredObjectDataValidationError(BaseValidationError):
- def __init__(self, name: str, value: list[tuple[str, str]]):
- super().__init__(self.message(name, value))
-
- @classmethod
- def message(cls, name, value, validation=None):
- _ = validation
- return (
- f"Workspace: '{name}' object(s) {[k[0] for k in value]} "
- f"are missing required children {[k[1] for k in value]}."
- )
-
-
class ShapeValidationError(BaseValidationError):
"""Error on shape validation."""
diff --git a/geoh5py/ui_json/enforcers.py b/geoh5py/ui_json/enforcers.py
deleted file mode 100644
index 7faf128df..000000000
--- a/geoh5py/ui_json/enforcers.py
+++ /dev/null
@@ -1,359 +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 __future__ import annotations
-
-from abc import ABC, abstractmethod
-from typing import Any
-from uuid import UUID
-
-from geoh5py.shared.exceptions import (
- AggregateValidationError,
- BaseValidationError,
- InCollectionValidationError,
- RequiredFormMemberValidationError,
- RequiredObjectDataValidationError,
- RequiredUIJsonParameterValidationError,
- RequiredWorkspaceObjectValidationError,
- TypeUIDValidationError,
- TypeValidationError,
- UUIDValidationError,
- ValueValidationError,
-)
-from geoh5py.shared.utils import SetDict, is_uuid
-
-
-class Enforcer(ABC):
- """
- Base class for rule enforcers.
-
- :param enforcer_type: Type of enforcer.
- :param validations: Value(s) to validate parameter value against.
- """
-
- enforcer_type: str = ""
-
- def __init__(self, validations: set):
- self.validations = validations
-
- @abstractmethod
- def rule(self, value: Any):
- """True if 'value' adheres to enforcers rule."""
-
- @abstractmethod
- def enforce(self, name: str, value: Any):
- """Enforces rule on 'name' parameter's 'value'."""
-
- def __eq__(self, other) -> bool:
- """Equal if same type and validations."""
-
- is_equal = False
- if isinstance(other, type(self)):
- is_equal = other.validations == self.validations
-
- return is_equal
-
- def __str__(self):
- return f"<{type(self).__name__}> : {self.validations}"
-
-
-class TypeEnforcer(Enforcer):
- """
- Enforces valid type(s).
-
- :param validations: Valid type(s) for parameter value.
- :raises TypeValidationError: If value is not a valid type.
- """
-
- enforcer_type: str = "type"
-
- def __init__(self, validations: set[type]):
- super().__init__(validations)
-
- def enforce(self, name: str, value: Any):
- """Administers rule to enforce type validation."""
-
- if not self.rule(value):
- raise TypeValidationError(
- name, type(value).__name__, [k.__name__ for k in self.validations]
- )
-
- def rule(self, value) -> bool:
- """True if value is one of the valid types."""
- return any(isinstance(value, k) for k in self.validations.union({type(None)}))
-
-
-class ValueEnforcer(Enforcer):
- """
- Enforces restricted value choices.
-
- :param validations: Valid parameter value(s).
- :raises ValueValidationError: If value is not a valid value
- choice.
- """
-
- enforcer_type = "value"
-
- def __init__(self, validations: set[Any]):
- super().__init__(validations)
-
- def enforce(self, name: str, value: Any):
- """Administers rule to enforce value validation."""
-
- if not self.rule(value):
- raise ValueValidationError(name, value, list(self.validations))
-
- def rule(self, value: Any) -> bool:
- """True if value is a valid choice."""
- return value in self.validations
-
-
-class TypeUIDEnforcer(Enforcer):
- """
- Enforces restricted geoh5 entity_type uid(s).
-
- :param validations: Valid geoh5py object type uid(s).
- :raises TypeValidationError: If value is not a valid type uid.
- """
-
- enforcer_type = "type_uid"
-
- def __init__(self, validations: set[str]):
- super().__init__(validations)
-
- def enforce(self, name: str, value: Any):
- """Administers rule to enforce type uid validation."""
-
- if not self.rule(value):
- raise TypeUIDValidationError(name, value, list(self.validations))
-
- def rule(self, value: Any) -> bool:
- """True if value is a valid type uid."""
- return self.validations == {""} or value.default_type_uid() in [
- UUID(k) for k in self.validations
- ]
-
-
-class UUIDEnforcer(Enforcer):
- """
- Enforces valid uuid string.
-
- :param validations: No validations needed, can be empty set.
- :raises UUIDValidationError: If value is not a valid uuid string.
- """
-
- enforcer_type = "uuid"
-
- def __init__(self, validations=None):
- super().__init__(validations)
-
- def enforce(self, name: str, value: Any):
- """Administers rule to check if valid uuid."""
-
- if not self.rule(value):
- raise UUIDValidationError(
- name,
- value,
- )
-
- def rule(self, value: Any) -> bool:
- """True if value is a valid uuid string."""
-
- if value is None:
- return True
-
- return is_uuid(value)
-
-
-class RequiredEnforcer(Enforcer):
- """
- Enforces required items in a collection.
-
- :param validations: Items that are required in the collection.
- :raises InCollectionValidationError: If collection is missing one of
- the required parameters/members.
- """
-
- enforcer_type = "required"
- validation_error = InCollectionValidationError
-
- def __init__(self, validations: set[str | tuple[str, str]]):
- super().__init__(validations)
-
- def enforce(self, name: str, value: Any):
- """Administers rule to check if required items in collection."""
-
- if not self.rule(value):
- raise self.validation_error(
- name,
- [k for k in self.validations if k not in self.collection(value)],
- )
-
- def rule(self, value: Any) -> bool:
- """True if all required parameters are in 'value' collection."""
- return all(k in self.collection(value) for k in self.validations)
-
- def collection(self, value: Any) -> list[Any]:
- """Returns the collection to check for required items."""
- return value
-
-
-class RequiredUIJsonParameterEnforcer(RequiredEnforcer):
- enforcer_type = "required_uijson_parameters"
- validation_error = RequiredUIJsonParameterValidationError
-
-
-class RequiredFormMemberEnforcer(RequiredEnforcer):
- enforcer_type = "required_form_members"
- validation_error = RequiredFormMemberValidationError
-
-
-class RequiredWorkspaceObjectEnforcer(RequiredEnforcer):
- enforcer_type = "required_workspace_object"
- validation_error = RequiredWorkspaceObjectValidationError
-
- def rule(self, value: Any) -> bool:
- """True if all objects are in the workspace."""
- validations = [value[k]["value"].uid for k in self.validations]
- return all(k in self.collection(value) for k in validations)
-
- def collection(self, value: dict[str, Any]) -> list[UUID]:
- return list(value["geoh5"].list_entities_name)
-
-
-class RequiredObjectDataEnforcer(Enforcer):
- enforcer_type = "required_object_data"
- validation_error = RequiredObjectDataValidationError
-
- def enforce(self, name: str, value: Any):
- """Administers rule to check if required items in collection."""
-
- if not self.rule(value):
- raise self.validation_error(
- name,
- [
- k
- for i, k in enumerate(self.validations)
- if value[k[1]]["value"].uid not in self.collection(value)[i]
- ],
- )
-
- def rule(self, value: Any) -> bool:
- """True if object/data have parent/child relationship."""
- return all(
- value[k[1]]["value"].uid in self.collection(value)[i]
- for i, k in enumerate(self.validations)
- )
-
- def collection(self, value: dict[str, Any]) -> list[list[UUID]]:
- """Returns list of children for all parents in validations."""
- return [
- [c.uid for c in value[k[0]]["value"].children] for k in self.validations
- ]
-
-
-class EnforcerPool:
- """
- Validate data on a collection of enforcers.
-
- :param name: Name of parameter.
- :param enforcers: List (pool) of enforcers.
- """
-
- enforcer_types = {
- "type": TypeEnforcer,
- "value": ValueEnforcer,
- "uuid": UUIDEnforcer,
- "type_uid": TypeUIDEnforcer,
- "required": RequiredEnforcer,
- "required_uijson_parameters": RequiredUIJsonParameterEnforcer,
- "required_form_members": RequiredFormMemberEnforcer,
- "required_workspace_object": RequiredWorkspaceObjectEnforcer,
- "required_object_data": RequiredObjectDataEnforcer,
- }
-
- def __init__(self, name: str, enforcers: list[Enforcer]):
- self.name = name
- self.enforcers: list[Enforcer] = enforcers
- self._errors: list[BaseValidationError] = []
-
- @classmethod
- def from_validations(
- cls,
- name: str,
- validations: SetDict,
- ) -> EnforcerPool:
- """
- Create enforcers pool from validations.
-
- :param name: Name of parameter.
- :param validations: Encodes validations as enforcer type and
- validation key value pairs.
- :param restricted_validations: 0.
-
- """
-
- return cls(name, cls._recruit(validations))
-
- @property
- def validations(self) -> SetDict:
- """Returns an enforcer type / validation dictionary from pool."""
- return SetDict(**{k.enforcer_type: k.validations for k in self.enforcers})
-
- @staticmethod
- def _recruit(validations: SetDict):
- """Recruit enforcers from validations."""
- return [EnforcerPool._recruit_enforcer(k, v) for k, v in validations.items()]
-
- @staticmethod
- def _recruit_enforcer(enforcer_type: str, validation: set) -> Enforcer:
- """
- Create enforcer from enforcer type and validation.
-
- :param enforcer_type: Type of enforcer to create.
- :param validation: Enforcer validation.
- """
-
- if enforcer_type not in EnforcerPool.enforcer_types:
- raise ValueError(f"Invalid enforcer type: {enforcer_type}.")
-
- return EnforcerPool.enforcer_types[enforcer_type](validation)
-
- def enforce(self, value: Any):
- """Enforce rules from all enforcers in the pool."""
-
- for enforcer in self.enforcers:
- self._capture_error(enforcer, value)
-
- self._raise_errors()
-
- def _capture_error(self, enforcer: Enforcer, value: Any):
- """Catch and store 'BaseValidationError's for aggregation."""
- try:
- enforcer.enforce(self.name, value)
- except BaseValidationError as err:
- self._errors.append(err)
-
- def _raise_errors(self):
- """Raise errors if any exist, aggregate if more than one."""
- if self._errors:
- if len(self._errors) > 1:
- raise AggregateValidationError(self.name, self._errors)
- raise self._errors.pop()
diff --git a/geoh5py/ui_json/parameters.py b/geoh5py/ui_json/parameters.py
deleted file mode 100644
index efce9cef9..000000000
--- a/geoh5py/ui_json/parameters.py
+++ /dev/null
@@ -1,171 +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 __future__ import annotations
-
-from typing import Any
-from uuid import UUID
-
-from geoh5py import Workspace
-from geoh5py.groups import PropertyGroup
-from geoh5py.shared.utils import SetDict
-from geoh5py.ui_json.enforcers import EnforcerPool
-
-
-Validation = dict[str, Any]
-
-
-class Parameter:
- """
- Basic parameter to store key/value data with validation capabilities.
-
- :param name: Parameter name.
- :param value: The parameters value.
- :param enforcers: A collection of enforcers.
- """
-
- static_validations: dict[str, Any] = {}
-
- def __init__(self, name: str, value: Any = None):
- self.name: str = name
- self._value: Any | None = None
- self._enforcers: EnforcerPool = EnforcerPool.from_validations(
- self.name, self.validations
- )
- if value is not None:
- self.value = value
-
- @property
- def validations(self):
- """Returns a dictionary of static validations."""
- return SetDict(**self.static_validations)
-
- @property
- def value(self):
- return self._value
-
- @value.setter
- def value(self, val):
- self._value = val
- self.validate()
-
- def validate(self):
- """Validates data against the pool of enforcers."""
- self._enforcers.enforce(self.value)
-
- def __str__(self):
- return f"<{type(self).__name__}> : '{self.name}' -> {self.value}"
-
-
-class DynamicallyRestrictedParameter(Parameter):
- """Parameter whose validations are set at runtime."""
-
- def __init__(
- self, name: str, restrictions: Any, enforcer_type="type", value: Any = None
- ):
- self._restrictions = restrictions
- self._enforcer_type = enforcer_type
- super().__init__(name, value)
-
- @property
- def restrictions(self):
- if not isinstance(self._restrictions, list):
- self._restrictions = {self._restrictions}
-
- return self._restrictions
-
- @property
- def validations(self):
- return SetDict(**{self._enforcer_type: self.restrictions})
-
-
-class ValueRestrictedParameter(DynamicallyRestrictedParameter):
- """Parameter with a restricted set of values."""
-
- def __init__(self, name: str, restrictions: Any, value: Any = None):
- super().__init__(name, restrictions, "value", value)
-
-
-class TypeRestrictedParameter(DynamicallyRestrictedParameter):
- """Parameter with a restricted set of types known at runtime only."""
-
- def __init__(self, name: str, restrictions: list[Any], value: Any = None):
- super().__init__(name, restrictions, "type", value)
-
-
-class TypeUIDRestrictedParameter(DynamicallyRestrictedParameter):
- """Parameter with a restricted set of type uids known at runtime only."""
-
- def __init__(self, name: str, restrictions: list[UUID], value: Any = None):
- super().__init__(name, restrictions, "type_uid", value)
-
-
-class StringParameter(Parameter):
- """Parameter for string values."""
-
- static_validations = {"type": str}
-
-
-class IntegerParameter(Parameter):
- """Parameter for integer values."""
-
- static_validations = {"type": int}
-
-
-class FloatParameter(Parameter):
- """Parameter for float values."""
-
- static_validations = {"type": float}
-
-
-class NumericParameter(Parameter):
- """Parameter for generic numeric values."""
-
- static_validations = {"type": [int, float]}
-
-
-class BoolParameter(Parameter):
- """Parameter for boolean values."""
-
- static_validations = {"type": bool}
-
- def __init__(self, name: str, value: bool = False):
- super().__init__(name, value)
-
-
-class StringListParameter(Parameter):
- """Parameter for list of strings."""
-
- static_validations = {"type": [list, str]}
-
- # TODO: introduce type alias handling so that TypeEnforcer(list[str], str)
- # is possible
-
-
-class WorkspaceParameter(Parameter):
- """Parameter for workspace objects."""
-
- static_validations = {"type": Workspace}
-
-
-class PropertyGroupParameter(Parameter):
- """Parameter for property group objects."""
-
- static_validations = {"type": PropertyGroup}
diff --git a/tests/ui_json/enforcers_test.py b/tests/ui_json/enforcers_test.py
deleted file mode 100644
index 9e068ccdf..000000000
--- a/tests/ui_json/enforcers_test.py
+++ /dev/null
@@ -1,213 +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 __future__ import annotations
-
-import uuid
-
-import numpy as np
-import pytest
-
-from geoh5py import Workspace
-from geoh5py.objects import Points
-from geoh5py.shared.exceptions import (
- AggregateValidationError,
- RequiredFormMemberValidationError,
- RequiredObjectDataValidationError,
- RequiredUIJsonParameterValidationError,
- RequiredWorkspaceObjectValidationError,
- TypeValidationError,
- UUIDValidationError,
- ValueValidationError,
-)
-from geoh5py.shared.utils import SetDict
-from geoh5py.ui_json.enforcers import (
- EnforcerPool,
- RequiredEnforcer,
- RequiredFormMemberEnforcer,
- RequiredObjectDataEnforcer,
- RequiredUIJsonParameterEnforcer,
- RequiredWorkspaceObjectEnforcer,
- TypeEnforcer,
- UUIDEnforcer,
- ValueEnforcer,
-)
-
-
-def test_enforcer_pool_recruit():
- validations = SetDict(
- type={str},
- value={"onlythis"},
- uuid={None},
- required={"me"},
- required_uijson_parameters={"me", "you"},
- required_form_members={"label", "value"},
- required_workspace_object={"data"},
- required_object_data={"object"},
- )
- enforcers = EnforcerPool._recruit(validations) # pylint: disable=protected-access
-
- assert enforcers == [
- TypeEnforcer({str}),
- ValueEnforcer({"onlythis"}),
- UUIDEnforcer({None}),
- RequiredEnforcer({"me"}),
- RequiredUIJsonParameterEnforcer({"me", "you"}),
- RequiredFormMemberEnforcer({"label", "value"}),
- RequiredWorkspaceObjectEnforcer({"data"}),
- RequiredObjectDataEnforcer({"object"}),
- ]
-
-
-def test_enforcer_pool_construction():
- pool = EnforcerPool("my_param", [TypeEnforcer({str})])
- assert pool.enforcers == [TypeEnforcer({str})]
-
-
-def test_enforcer_pool_validations():
- validations = SetDict(type=str, value="onlythis")
- pool = EnforcerPool.from_validations("my_param", validations)
- assert pool.validations == validations
- pool = EnforcerPool("my_param", [TypeEnforcer({str}), ValueEnforcer({"onlythis"})])
- assert pool.validations == validations
-
-
-def test_enforcer_pool_from_validations():
- pool = EnforcerPool.from_validations("my_param", {"type": str})
- assert pool.enforcers == [TypeEnforcer(str)]
-
-
-def test_enforcer_pool_raises_single_error():
- enforcers = EnforcerPool("my_param", [TypeEnforcer({str})])
- enforcers.enforce("1")
- msg = "Type 'int' provided for 'my_param' is invalid. "
- msg += "Must be: 'str'."
- with pytest.raises(TypeValidationError, match=msg):
- enforcers.enforce(1)
-
-
-def test_enforcer_pool_raises_aggregate_error():
- enforcers = EnforcerPool(
- "my_param", [TypeEnforcer({str}), ValueEnforcer({"onlythis"})]
- )
- enforcers.enforce("onlythis")
- msg = (
- "Validation of 'my_param' collected 2 errors:\n\t"
- "0. Type 'int' provided for 'my_param' is invalid"
- )
- with pytest.raises(AggregateValidationError, match=msg):
- enforcers.enforce(1)
-
-
-def test_enforcer_str():
- enforcer = TypeEnforcer(validations={str})
- assert str(enforcer) == " : {}"
-
-
-def test_type_enforcer():
- enforcer = TypeEnforcer(validations={int})
- assert enforcer.validations == {int}
- enforcer.enforce("test", 1)
- msg = "Type 'float' provided for 'test' is invalid. Must be: 'int'."
- with pytest.raises(TypeValidationError, match=msg):
- enforcer.enforce("test", 1.0)
-
- enforcer = TypeEnforcer(validations=[int, str])
- assert enforcer.validations == [int, str]
-
-
-def test_value_enforcer():
- enforcer = ValueEnforcer(validations=[1, 2, 3])
- enforcer.enforce("test", 1)
- msg = "Value '4' provided for 'test' is invalid. "
- msg += "Must be one of: '1', '2', '3'."
- with pytest.raises(ValueValidationError, match=msg):
- enforcer.enforce("test", 4)
-
-
-def test_uuid_enforcer():
- enforcer = UUIDEnforcer()
- enforcer.enforce("test", str(uuid.uuid4()))
- msg = "Parameter 'test' with value 'notachance' "
- msg += "is not a valid uuid string."
- with pytest.raises(UUIDValidationError, match=msg):
- enforcer.enforce("test", "notachance")
-
-
-def test_required_uijson_parameter_enforcer():
- enforcer = RequiredUIJsonParameterEnforcer(["my_param"])
- msg = r"UIJson: 'my_param' is missing required parameter\(s\): \['my_param'\]."
- with pytest.raises(RequiredUIJsonParameterValidationError, match=msg):
- enforcer.enforce("my_param", {"label": "my param"})
-
-
-def test_required_form_member_enforcer():
- enforcer = RequiredFormMemberEnforcer(["my_member"])
- msg = r"Form: 'my_member' is missing required member\(s\): \['my_member'\]."
- with pytest.raises(RequiredFormMemberValidationError, match=msg):
- enforcer.enforce("my_member", {"label": "my member"})
-
-
-def test_required_workspace_object_enforcer(tmp_path):
- geoh5 = Workspace(tmp_path / "working_file.geoh5")
- pts = Points.create(geoh5, vertices=np.random.rand(10, 3), name="my_points")
- other_geoh5 = Workspace(tmp_path / "other_file.geoh5")
- other_pts = Points.create(
- other_geoh5, vertices=np.random.rand(10, 3), name="my_other_points"
- )
-
- data = {"geoh5": geoh5, "my_points": {"value": pts}}
- validations = ["my_points"]
- enforcer = RequiredWorkspaceObjectEnforcer(validations)
- enforcer.enforce(str(geoh5.h5file.stem), data)
-
- data["my_points"] = {"value": other_pts}
- msg = r"Workspace: 'working_file' is missing required object\(s\): \['my_points'\]."
- with pytest.raises(RequiredWorkspaceObjectValidationError, match=msg):
- enforcer.enforce(str(geoh5.h5file.stem), data)
-
-
-def test_required_object_data_enforcer(tmp_path):
- geoh5 = Workspace(tmp_path / "working_file.geoh5")
- pts = Points.create(geoh5, vertices=np.random.rand(10, 3), name="my_points")
- my_data = pts.add_data({"my_data": {"values": np.random.rand(10)}})
- other_pts = Points.create(
- geoh5, vertices=np.random.rand(10, 3), name="my_other_points"
- )
- the_wrong_data = other_pts.add_data(
- {"my_other_data": {"values": np.random.rand(10)}}
- )
-
- data = {
- "geoh5": geoh5,
- "object": {"value": pts},
- "data": {"value": my_data},
- }
- validations = [("object", "data")]
- enforcer = RequiredObjectDataEnforcer(validations)
- enforcer.enforce(str(geoh5.h5file.stem), data)
-
- data["data"]["value"] = the_wrong_data
- msg = (
- r"Workspace: 'working_file' object\(s\) \['object'\] "
- r"are missing required children \['data'\]."
- )
- with pytest.raises(RequiredObjectDataValidationError, match=msg):
- enforcer.enforce(str(geoh5.h5file.stem), data)
diff --git a/tests/ui_json/exceptions_test.py b/tests/ui_json/exceptions_test.py
deleted file mode 100644
index b4316e017..000000000
--- a/tests/ui_json/exceptions_test.py
+++ /dev/null
@@ -1,59 +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 __future__ import annotations
-
-import pytest
-
-from geoh5py.shared.exceptions import (
- RequiredFormMemberValidationError,
- RequiredObjectDataValidationError,
- RequiredUIJsonParameterValidationError,
- RequiredWorkspaceObjectValidationError,
-)
-
-
-def test_required_form_member_validation_error():
- msg = r"Form: 'test' is missing required member\(s\): \['member1', 'member2'\]."
- with pytest.raises(RequiredFormMemberValidationError, match=msg):
- raise RequiredFormMemberValidationError("test", ["member1", "member2"])
-
-
-def test_required_ui_json_parameter_validation_error():
- msg = r"UIJson: 'test' is missing required parameter\(s\): \['param1', 'param2'\]."
- with pytest.raises(RequiredUIJsonParameterValidationError, match=msg):
- raise RequiredUIJsonParameterValidationError("test", ["param1", "param2"])
-
-
-def test_required_workspace_object_validation_error():
- msg = r"Workspace: 'test' is missing required object\(s\): \['obj1', 'obj2'\]."
- with pytest.raises(RequiredWorkspaceObjectValidationError, match=msg):
- raise RequiredWorkspaceObjectValidationError("test", ["obj1", "obj2"])
-
-
-def test_required_object_data_validation_error():
- msg = (
- r"Workspace: 'test' object\(s\) \['object1', 'object2'] are "
- r"missing required children \['data1', 'data2'\]."
- )
- with pytest.raises(RequiredObjectDataValidationError, match=msg):
- raise RequiredObjectDataValidationError(
- "test", [("object1", "data1"), ("object2", "data2")]
- )
diff --git a/tests/ui_json/parameter_test.py b/tests/ui_json/parameter_test.py
deleted file mode 100644
index c71180873..000000000
--- a/tests/ui_json/parameter_test.py
+++ /dev/null
@@ -1,129 +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 __future__ import annotations
-
-import pytest
-
-from geoh5py.shared.exceptions import TypeValidationError, ValueValidationError
-from geoh5py.ui_json.parameters import (
- BoolParameter,
- FloatParameter,
- IntegerParameter,
- Parameter,
- StringListParameter,
- StringParameter,
- TypeRestrictedParameter,
- ValueRestrictedParameter,
-)
-
-
-# pylint: disable=protected-access
-
-
-def test_skip_validation_on_none_value():
- param = StringParameter("my_param", None)
- assert param.value is None
-
-
-def test_parameter_validations_on_setting():
- param = StringParameter("my_param")
- param.value = "me"
- msg = "Type 'int' provided for 'my_param' is invalid. Must be: 'str'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = 1
-
-
-def test_parameter_str_representation():
- param = Parameter("my_param")
- assert str(param) == " : 'my_param' -> None"
-
-
-def test_string_parameter_type_validation():
- param = StringParameter("my_param")
- msg = "Type 'int' provided for 'my_param' is invalid. "
- msg += "Must be: 'str'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = 1
-
-
-def test_string_parameter_optional_validations():
- param = StringParameter("my_param")
- param.value = None
- param.value = "this is ok"
- msg = "Type 'int' provided for 'my_param' is invalid. Must be: 'str'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = 1
-
-
-def test_integer_parameter_type_validation():
- param = IntegerParameter("my_param")
- msg = "Type 'str' provided for 'my_param' is invalid. "
- msg += "Must be: 'int'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = "1"
-
-
-def test_float_parameter_type_validation():
- param = FloatParameter("my_param")
- msg = "Type 'int' provided for 'my_param' is invalid. "
- msg += "Must be: 'float'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = 1
-
-
-def test_bool_parameter_default():
- param = BoolParameter("my_param")
- assert param.value is False
-
-
-def test_bool_parameter_type_validation():
- param = BoolParameter("my_param")
- msg = "Type 'str' provided for 'my_param' is invalid. "
- msg += "Must be: 'bool'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = "butwhy?"
-
-
-def test_string_list_parameter_type_validation():
- param = StringListParameter("my_param")
- param.value = "this is ok"
- param.value = ["this", "is", "also", "ok"]
- msg = "Type 'int' provided for 'my_param' is invalid. Must be one of:"
- with pytest.raises(TypeValidationError, match=msg) as info:
- param.value = 1
-
- assert all(k in str(info.value) for k in ["list", "str"])
-
-
-def test_type_restricted_parameter_type_validation():
- param = TypeRestrictedParameter("my_param", [str])
- param.value = "this is ok"
- msg = "Type 'int' provided for 'my_param' is invalid. Must be: 'str'."
- with pytest.raises(TypeValidationError, match=msg):
- param.value = 1
-
-
-def test_value_restricted_parameter_type_validation():
- param = ValueRestrictedParameter("my_param", [1, 2, 3])
- param.value = 1
- msg = "Value '1' provided for 'my_param' is invalid. Must be one of: '1', '2', '3'."
- with pytest.raises(ValueValidationError, match=msg):
- param.value = "1"