"""This module contains the schema classes for the medrecord module."""from__future__importannotationsfromenumimportEnum,autofromtypingimport(TYPE_CHECKING,Dict,List,Literal,Optional,Tuple,TypeAlias,Union,overload,)frommedmodels._medmodelsimport(PyAttributeDataType,PyAttributeType,PyGroupSchema,PySchema,PySchemaType,)frommedmodels.medrecord.datatypeimport(DataType,DateTime,Duration,Float,Int,Null,Option,)frommedmodels.medrecord.datatypeimportUnionasDataTypeUnionfrommedmodels.medrecord.typesimport(Attributes,EdgeIndex,MedRecordAttribute,NodeIndex,)ifTYPE_CHECKING:frommedmodels.medrecord.medrecordimportMedRecordfrommedmodels.medrecord.typesimportGroup
[docs]classAttributeType(Enum):"""Enumeration of attribute types."""Categorical=auto()Continuous=auto()Temporal=auto()Unstructured=auto()@staticmethoddef_from_py_attribute_type(py_attribute_type:PyAttributeType)->AttributeType:"""Converts a PyAttributeType to an AttributeType. Args: py_attribute_type (PyAttributeType): The PyAttributeType to convert. Returns: AttributeType: The converted AttributeType. """ifpy_attribute_type==PyAttributeType.Categorical:returnAttributeType.Categoricalifpy_attribute_type==PyAttributeType.Continuous:returnAttributeType.Continuousifpy_attribute_type==PyAttributeType.Temporal:returnAttributeType.Temporalifpy_attribute_type==PyAttributeType.Unstructured:returnAttributeType.Unstructuredmsg="Should never be reached"raiseNotImplementedError(msg)
[docs]@staticmethoddefinfer(data_type:DataType)->AttributeType:"""Infers the attribute type from the data type. Args: data_type (DataType): The data type to infer the attribute type from. Returns: AttributeType: The inferred attribute type. """returnAttributeType._from_py_attribute_type(PyAttributeType.infer(data_type._inner()))
def_into_py_attribute_type(self)->PyAttributeType:"""Converts an AttributeType to a PyAttributeType. Returns: PyAttributeType: The converted PyAttributeType. """ifself==AttributeType.Categorical:returnPyAttributeType.Categoricalifself==AttributeType.Continuous:returnPyAttributeType.Continuousifself==AttributeType.Temporal:returnPyAttributeType.Temporalifself==AttributeType.Unstructured:returnPyAttributeType.Unstructuredmsg="Should never be reached"raiseNotImplementedError(msg)
[docs]def__repr__(self)->str:"""Returns a string representation of the AttributeType instance. Returns: str: String representation of the attribute type. """returnf"AttributeType.{self.name}"
[docs]def__str__(self)->str:"""Returns a string representation of the AttributeType instance. Returns: str: String representation of the attribute type. """returnself.name
[docs]def__hash__(self)->int:"""Returns the hash of the AttributeType instance. Returns: int: The hash of the AttributeType instance. """returnhash(self.name)
[docs]def__eq__(self,value:object)->bool:"""Compares the AttributeType instance to another object for equality. Args: value (object): The object to compare against. Returns: bool: True if the objects are equal, False otherwise. """ifisinstance(value,PyAttributeType):returnself._into_py_attribute_type()==valueifisinstance(value,AttributeType):returnstr(self)==str(value)returnFalse
[docs]classGroupSchema:"""A schema for a group of nodes and edges."""_group_schema:PyGroupSchemadef__init__(self,*,nodes:Optional[Dict[MedRecordAttribute,Union[DataType,AttributeDataType],],]=None,edges:Optional[Dict[MedRecordAttribute,Union[DataType,AttributeDataType],],]=None,)->None:"""Initializes a new instance of GroupSchema. Args: nodes (Dict[MedRecordAttribute, Union[DataType, AttributeDataType]]): A dictionary mapping node attributes to their data types and optional attribute types. Defaults to an empty dictionary. When no attribute type is provided, it is inferred from the data type. edges (Dict[MedRecordAttribute, Union[DataType, AttributeDataType]]): A dictionary mapping edge attributes to their data types and optional attribute types. Defaults to an empty dictionary. When no attribute type is provided, it is inferred from the data type. """ifedgesisNone:edges={}ifnodesisNone:nodes={}def_convert_input(input:Union[DataType,AttributeDataType],)->PyAttributeDataType:ifisinstance(input,tuple):returnPyAttributeDataType(input[0]._inner(),input[1]._into_py_attribute_type())returnPyAttributeDataType(input._inner(),PyAttributeType.infer(input._inner()))self._group_schema=PyGroupSchema(nodes={x:_convert_input(nodes[x])forxinnodes},edges={x:_convert_input(edges[x])forxinedges},)@classmethoddef_from_py_group_schema(cls,group_schema:PyGroupSchema)->GroupSchema:"""Creates a GroupSchema instance from an existing PyGroupSchema. Args: group_schema (PyGroupSchema): The PyGroupSchema instance to convert. Returns: GroupSchema: A new GroupSchema instance. """new_group_schema=cls()new_group_schema._group_schema=group_schemareturnnew_group_schema@propertydefnodes(self)->AttributesSchema:"""Returns the node attributes in the GroupSchema instance. Returns: AttributesSchema: An AttributesSchema object containing the node attributes and their data types. """def_convert_node(input:PyAttributeDataType,)->AttributeDataType:# SAFETY: The typing is guaranteed to be correctreturn(DataType._from_py_data_type(input.data_type),AttributeType._from_py_attribute_type(input.attribute_type),)# pyright: ignore[reportReturnType]return{x:_convert_node(self._group_schema.nodes[x])forxinself._group_schema.nodes}@propertydefedges(self)->AttributesSchema:"""Returns the edge attributes in the GroupSchema instance. Returns: AttributesSchema: An AttributesSchema object containing the edge attributes and their data types. """def_convert_edge(input:PyAttributeDataType,)->AttributeDataType:# SAFETY: The typing is guaranteed to be correctreturn(DataType._from_py_data_type(input.data_type),AttributeType._from_py_attribute_type(input.attribute_type),)# pyright: ignore[reportReturnType]return{x:_convert_edge(self._group_schema.edges[x])forxinself._group_schema.edges}
[docs]defvalidate_node(self,index:NodeIndex,attributes:Attributes)->None:"""Validates the attributes of a node against the schema. Args: index (NodeIndex): The index of the node. attributes (Attributes): The attributes of the node. """self._group_schema.validate_node(index,attributes)
[docs]defvalidate_edge(self,index:EdgeIndex,attributes:Attributes)->None:"""Validates the attributes of an edge against the schema. Args: index (EdgeIndex): The index of the edge. attributes (Attributes): The attributes of the edge. """self._group_schema.validate_edge(index,attributes)
[docs]classSchemaType(Enum):"""Enumeration of schema types."""Provided=auto()Inferred=auto()@staticmethoddef_from_py_schema_type(py_schema_type:PySchemaType)->SchemaType:"""Converts a PySchemaType to a SchemaType. Args: py_schema_type (PySchemaType): The PySchemaType to convert. Returns: SchemaType: The converted SchemaType. """ifpy_schema_type==PySchemaType.Provided:returnSchemaType.Providedifpy_schema_type==PySchemaType.Inferred:returnSchemaType.Inferredmsg="Should never be reached"raiseNotImplementedError(msg)def_into_py_schema_type(self)->PySchemaType:"""Converts a SchemaType to a PySchemaType. Returns: PySchemaType: The converted PySchemaType. """ifself==SchemaType.Provided:returnPySchemaType.Providedifself==SchemaType.Inferred:returnPySchemaType.Inferredmsg="Should never be reached"raiseNotImplementedError(msg)
[docs]classSchema:"""A schema for a collection of groups."""_schema:PySchemadef__init__(self,*,groups:Optional[Dict[Group,GroupSchema]]=None,ungrouped:Optional[GroupSchema]=None,schema_type:Optional[SchemaType]=None,)->None:"""Initializes a new instance of Schema. Args: groups (Dict[Group, GroupSchema], optional): A dictionary of group names to their schemas. Defaults to None. ungrouped (Optional[GroupSchema], optional): The group schema for all nodes not in a group. If not provided, an empty group schema is used. Defaults to None. schema_type (Optional[SchemaType], optional): The type of the schema. If not provided, the schema is of type provided. Defaults to None. """ifnotungrouped:ungrouped=GroupSchema()ifgroupsisNone:groups={}ifschema_type:self._schema=PySchema(groups={x:groups[x]._group_schemaforxingroups},ungrouped=ungrouped._group_schema,schema_type=schema_type._into_py_schema_type(),)else:self._schema=PySchema(groups={x:groups[x]._group_schemaforxingroups},ungrouped=ungrouped._group_schema,)
[docs]@classmethoddefinfer(cls,medrecord:MedRecord)->Schema:"""Infers a schema from a MedRecord instance. Args: medrecord (MedRecord): The MedRecord instance to infer the schema from. Returns: Schema: The inferred schema. """new_schema=cls()new_schema._schema=PySchema.infer(medrecord._medrecord)returnnew_schema
@classmethoddef_from_py_schema(cls,schema:PySchema)->Schema:"""Creates a Schema instance from an existing PySchema. Args: schema (PySchema): The PySchema instance to convert. Returns: Schema: A new Schema instance. """new_schema=cls()new_schema._schema=schemareturnnew_schema@propertydefgroups(self)->List[Group]:"""Lists all the groups in the Schema instance. Returns: List[Group]: A list of groups. """returnself._schema.groups
[docs]defgroup(self,group:Group)->GroupSchema:"""Retrieves the schema for a specific group. Args: group (Group): The name of the group. Returns: GroupSchema: The schema for the specified group. Raises: ValueError: If the group does not exist in the schema. """# noqa: DOC502returnGroupSchema._from_py_group_schema(self._schema.group(group))
@propertydefungrouped(self)->GroupSchema:"""Retrieves the group schema for all ungrouped nodes and edges. Returns: GroupSchema: The ungrouped group schema. """returnGroupSchema._from_py_group_schema(self._schema.ungrouped)@propertydefschema_type(self)->SchemaType:"""Retrieves the schema type. Returns: SchemaType: The schema type. """returnSchemaType._from_py_schema_type(self._schema.schema_type)
[docs]defvalidate_node(self,index:NodeIndex,attributes:Attributes,group:Optional[Group]=None)->None:"""Validates the attributes of a node against the schema. Args: index (NodeIndex): The index of the node. attributes (Attributes): The attributes of the node. group (Optional[Group], optional): The group to validate the node against. If not provided, the ungrouped schema is used. Defaults to None. """self._schema.validate_node(index,attributes,group)
[docs]defvalidate_edge(self,index:EdgeIndex,attributes:Attributes,group:Optional[Group]=None)->None:"""Validates the attributes of an edge against the schema. Args: index (EdgeIndex): The index of the edge. attributes (Attributes): The attributes of the edge. group (Optional[Group], optional): The group to validate the edge against. If not provided, the ungrouped schema is used. Defaults to None. """self._schema.validate_edge(index,attributes,group)
[docs]defset_node_attribute(self,attribute:MedRecordAttribute,data_type:DataType,attribute_type:Optional[AttributeType]=None,group:Optional[Group]=None,)->None:"""Sets the data type and attribute type of a node attribute. If a data type for the attribute already exists, it is overwritten. Args: attribute (MedRecordAttribute): The name of the attribute. data_type (DataType): The data type of the attribute. attribute_type (Optional[AttributeType], optional): The attribute type of the attribute. If not provided, the attribute type is inferred from the data type. Defaults to None. group (Optional[Group], optional): The group to set the attribute for. If no schema for the group exists, a new schema is created. If not provided, the ungrouped schema is used. Defaults to None. """ifnotattribute_type:attribute_type=AttributeType.infer(data_type)self._schema.set_node_attribute(attribute,data_type._inner(),attribute_type._into_py_attribute_type(),group,)
[docs]defset_edge_attribute(self,attribute:MedRecordAttribute,data_type:DataType,attribute_type:Optional[AttributeType]=None,group:Optional[Group]=None,)->None:"""Sets the data type and attribute type of an edge attribute. If a data type for the attribute already exists, it is overwritten. Args: attribute (MedRecordAttribute): The name of the attribute. data_type (DataType): The data type of the attribute. attribute_type (Optional[AttributeType], optional): The attribute type of the attribute. If not provided, the attribute type is inferred from the data type. Defaults to None. group (Optional[Group], optional): The group to set the attribute for. If no schema for this group exists, a new schema is created. If not provided, the ungrouped schema is used. Defaults to None. """ifnotattribute_type:attribute_type=AttributeType.infer(data_type)self._schema.set_edge_attribute(attribute,data_type._inner(),attribute_type._into_py_attribute_type(),group,)
[docs]defupdate_node_attribute(self,attribute:MedRecordAttribute,data_type:DataType,attribute_type:Optional[AttributeType]=None,group:Optional[Group]=None,)->None:"""Updates the data type and attribute type of a node attribute. If a data type for the attribute already exists, it is merged with the new data type. Args: attribute (MedRecordAttribute): The name of the attribute. data_type (DataType): The data type of the attribute. attribute_type (Optional[AttributeType], optional): The attribute type of the attribute. If not provided, the attribute type is inferred from the data type. Defaults to None. group (Optional[Group], optional): The group to update the attribute for. If no schema for this group exists, a new schema is created. If not provided, the ungrouped schema is used. Defaults to None. """ifnotattribute_type:attribute_type=AttributeType.infer(data_type)self._schema.update_node_attribute(attribute,data_type._inner(),attribute_type._into_py_attribute_type(),group,)
[docs]defupdate_edge_attribute(self,attribute:MedRecordAttribute,data_type:DataType,attribute_type:Optional[AttributeType]=None,group:Optional[Group]=None,)->None:"""Updates the data type and attribute type of an edge attribute. If a data type for the attribute already exists, it is merged with the new data type. Args: attribute (MedRecordAttribute): The name of the attribute. data_type (DataType): The data type of the attribute. attribute_type (Optional[AttributeType], optional): The attribute type of the attribute. If not provided, the attribute type is inferred from the data type. Defaults to None. group (Optional[Group], optional): The group to update the attribute for. If no schema for this group exists, a new schema is created. If not provided, the ungrouped schema is used. Defaults to None. """ifnotattribute_type:attribute_type=AttributeType.infer(data_type)self._schema.update_edge_attribute(attribute,data_type._inner(),attribute_type._into_py_attribute_type(),group,)
[docs]defremove_node_attribute(self,attribute:MedRecordAttribute,group:Optional[Group]=None)->None:"""Removes a node attribute from the schema. Args: attribute (MedRecordAttribute): The name of the attribute to remove. group (Optional[Group], optional): The group to remove the attribute from. If not provided, the ungrouped schema is used. Defaults to None. """self._schema.remove_node_attribute(attribute,group)
[docs]defremove_edge_attribute(self,attribute:MedRecordAttribute,group:Optional[Group]=None)->None:"""Removes an edge attribute from the schema. Args: attribute (MedRecordAttribute): The name of the attribute to remove. group (Optional[Group], optional): The group to remove the attribute from. If not provided, the ungrouped schema is used. Defaults to None. """self._schema.remove_edge_attribute(attribute,group)
[docs]defadd_group(self,group:Group,group_schema:GroupSchema)->None:"""Adds a new group to the schema. Args: group (Group): The name of the group. group_schema (GroupSchema): The schema for the group. """self._schema.add_group(group,group_schema._group_schema)
[docs]defremove_group(self,group:Group)->None:"""Removes a group from the schema. Args: group (Group): The name of the group to remove. """self._schema.remove_group(group)
[docs]deffreeze(self)->None:"""Freezes the schema. No changes are automatically inferred."""self._schema.freeze()
[docs]defunfreeze(self)->None:"""Unfreezes the schema. Changes are automatically inferred."""self._schema.unfreeze()