Source code for geoh5py.groups.property_group

#  Copyright (c) 2024 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 <https://www.gnu.org/licenses/>.

from __future__ import annotations

import uuid
from abc import ABC
from collections.abc import Iterable
from typing import TYPE_CHECKING

from geoh5py.data import Data, DataAssociationEnum

if TYPE_CHECKING:
    from geoh5py.objects import ObjectBase
    from geoh5py.shared import Entity


[docs] class PropertyGroup(ABC): """ Property group listing data children of an object. This group is not registered to the workspace and only visible to the parent object. """ _attribute_map = { "Association": "association", "Group Name": "name", "ID": "uid", "Properties": "properties", "Property Group Type": "property_group_type", } _name: str _uid: uuid.UUID def __init__( self, parent: ObjectBase, name=None, on_file=False, uid=None, **kwargs ): self.name = name or "property_group" self.uid = uid or uuid.uuid4() self._allow_delete = True self.on_file = on_file self._association: DataAssociationEnum = DataAssociationEnum.VERTEX if not hasattr(parent, "_property_groups"): raise AttributeError( f"Parent {parent} must have a 'property_groups' attribute" ) self._parent: ObjectBase = parent self._properties: list[uuid.UUID] | None = None self._property_group_type = "Multi-element" parent.add_children([self]) for attr, item in kwargs.items(): try: if attr in self._attribute_map: attr = self._attribute_map[attr] setattr(self, attr, item) except AttributeError: continue self.parent.workspace.register_property_group(self)
[docs] def add_properties(self, data: Data | list[Data | uuid.UUID] | uuid.UUID): """ Remove data from the properties. """ if isinstance(data, (Data, uuid.UUID)): data = [data] properties = self._properties or [] for elem in data: if isinstance(elem, uuid.UUID): entity = self.parent.get_entity(elem)[0] elif isinstance(elem, Data) and elem in self.parent.children: entity = elem else: continue if isinstance(entity, Data) and entity.uid not in properties: properties.append(entity.uid) if properties: self._properties = properties self.parent.workspace.add_or_update_property_group(self)
@property def allow_delete(self) -> bool: """ :obj:`bool` Allow deleting the group """ return self._allow_delete @allow_delete.setter def allow_delete(self, value: bool): if not isinstance(value, bool): raise TypeError("allow_delete must be a boolean") self._allow_delete = value @property def association(self) -> DataAssociationEnum: """ :obj:`~geoh5py.data.data_association_enum.DataAssociationEnum` Data association """ return self._association @association.setter def association(self, value: str | DataAssociationEnum): if isinstance(value, str): value = getattr(DataAssociationEnum, value.upper()) if not isinstance(value, DataAssociationEnum): raise TypeError( f"Association must be 'VERTEX', 'CELL' or class of type {DataAssociationEnum}" ) self._association = value @property def attribute_map(self) -> dict: """ :obj:`dict` Attribute names mapping between geoh5 and geoh5py """ return self._attribute_map @property def name(self) -> str: """ :obj:`str` Name of the group """ return self._name @name.setter def name(self, new_name: str): if not isinstance(new_name, str): raise TypeError("Name must be a string") self._name = new_name @property def on_file(self): """ Property group is on geoh5 file. """ return self._on_file @on_file.setter def on_file(self, value: bool): if not isinstance(value, bool): raise TypeError("Attribute 'on_file' must be a boolean.") self._on_file = value @property def parent(self) -> Entity: """ The parent :obj:`~geoh5py.objects.object_base.ObjectBase` """ return self._parent @property def properties(self) -> list[uuid.UUID] | None: """ List of unique identifiers for the :obj:`~geoh5py.data.data.Data` contained in the property group. """ return self._properties @properties.setter def properties(self, uids: list[str | uuid.UUID]): if self._properties is not None: raise UserWarning( "Cannot modify properties of an existing property group. " "Consider using 'add_properties'." ) if not isinstance(uids, Iterable): return properties = [] for uid in uids: if isinstance(uid, str): uid = uuid.UUID(uid) properties.append(uid) if not all(isinstance(uid, uuid.UUID) for uid in properties): raise TypeError("All uids must be of type uuid.UUID") self._properties = properties @property def property_group_type(self) -> str: return self._property_group_type @property_group_type.setter def property_group_type(self, group_type: str): self._property_group_type = group_type
[docs] def remove_properties(self, data: Data | list[Data | uuid.UUID] | uuid.UUID): """ Remove data from the properties. """ if isinstance(data, (Data, uuid.UUID)): data = [data] if self._properties is None: return for elem in data: if isinstance(elem, uuid.UUID): entity = self.parent.get_entity(elem)[0] elif isinstance(elem, Data) and elem in self.parent.children: entity = elem else: continue if entity is not None and entity.uid in self._properties: self._properties.remove(entity.uid) self.parent.workspace.add_or_update_property_group(self)
@property def uid(self) -> uuid.UUID: """ :obj:`uuid.UUID` Unique identifier """ return self._uid @uid.setter def uid(self, uid: str | uuid.UUID): if isinstance(uid, str): uid = uuid.UUID(uid) if not isinstance(uid, uuid.UUID): raise TypeError(f"Could not convert input uid {uid} to type uuid.UUID") self._uid = uid