Source code for pynxxas.nexus.models
"""NeXus model"""
import pydantic
from typing import Union
from ..nxdl import models as nxdl_models
from ..nxdl import load_definition as load_nxdl_definition
[docs]
def load_model(name: str, **repo_options) -> pydantic.BaseModel:
return _NexusModelCreator(repo_options).create(name)
class _NexusModelCreator:
def __init__(self, repo_options: dict) -> None:
self._repo_options = repo_options
self._definitions = dict()
def create(self, name: str):
self._create_group(self._get_definition(name))
def _create_group(
self,
nxclass: Union[nxdl_models.Definition, nxdl_models.Group],
*args,
indent=0,
):
if isinstance(nxclass, nxdl_models.Definition):
nxclass_parent = self._get_definition(nxclass.extends)
assert nxclass_parent.type == "group"
else:
nxclass_parent = self._get_definition(nxclass.type)
# nxclass inherits from nxclass_parent while overwriting attributes,
# fields and groups.
# TODO: use pydantic.create_model to create a merged model
# from nxclass and nxclass_parent
# Circular sub-groups: NXgeometry <-> NXtranslation
self._print(indent, nxclass.name, nxclass.type, *args)
indent += 1
if indent > 5:
return # circular dependencies
base_attributes = {attr.name: attr for attr in nxclass_parent.attribute}
overwrite_attributes = {attr.name: attr for attr in nxclass.attribute}
attributes = {**base_attributes, **overwrite_attributes}
base_fields = {field.name: field for field in nxclass_parent.field}
overwrite_fields = {field.name: field for field in nxclass.field}
fields = {**base_fields, **overwrite_fields}
base_groups = {group.name: group for group in nxclass_parent.group}
overwrite_groups = {group.name: group for group in nxclass.group}
groups = {**base_groups, **overwrite_groups}
for attr in attributes.values():
occurs = _occurs(1, 1, attr.optional, attr.recommended)
self._print(indent, attr.name, attr.type, occurs)
for field in fields.values():
occurs = _occurs(
field.minOccurs, field.maxOccurs, field.optional, field.recommended
)
self._print(indent, field.name, field.type, occurs)
for group in groups.values():
occurs = _occurs(
group.minOccurs, group.maxOccurs, group.optional, group.recommended
)
self._create_group(group, occurs, indent=indent)
def _print(self, indent: int, *args):
print(" " * indent, *args)
def _get_definition(self, name: str) -> nxdl_models.Definition:
definition = self._definitions.get(name)
if definition:
return definition
definition = load_nxdl_definition(name, **self._repo_options)
self._definitions[name] = definition
return definition
def _occurs(minOccurs, maxOccurs, optional, recommended):
optional = optional or recommended
if optional:
minOccurs = 0
if not isinstance(maxOccurs, int):
maxOccurs = float("inf")
return f"[{minOccurs}, {maxOccurs}]"