from __future__ import annotations
from pydantic import BaseModel, Field, field_validator, ConfigDict
from nxtomomill.settings import Tomo
from nxtomomill.models.utils import convert_str_to_tuple, is_url_path, filter_str_def
from silx.io.url import DataUrl
[docs]class EntriesAndTitlesSection(BaseModel):
model_config = ConfigDict(
validate_assignment=True, arbitrary_types_allowed=True, validate_by_name=True
)
entries: tuple[DataUrl, ...] = Field(
default=tuple(), description="List of root/init entries to convert"
)
sub_entries_to_ignore: tuple[DataUrl, ...] = Field(
default=tuple(), description="List of sub entries to ignore"
)
init_titles: tuple[str, ...] = Field(
default=Tomo.H5.INIT_TITLES, description="Titles for initialization"
)
zseries_init_titles: tuple[str, ...] = Field(
default=Tomo.H5.ZSERIE_INIT_TITLES,
description="Titles for z-serie initialization",
alias="zserie_init_titles",
)
multitomo_init_titles: tuple[str, ...] = Field(
default=Tomo.H5.MULTITOMO_INIT_TITLES,
description="Titles for multi-tomo initialization",
)
back_and_forth_init_titles: tuple[str, ...] = Field(
default=Tomo.H5.BACK_AND_FORTH_INIT_TITLES,
description="Titles for back-and-forth initialization",
)
dark_titles: tuple[str, ...] = Field(
default=Tomo.H5.DARK_TITLES,
description="Titles to determine if the bliss scan is a set of dark",
)
flat_titles: tuple[str, ...] = Field(
default=Tomo.H5.FLAT_TITLES,
description="Titles to determine if the bliss scan is a set of flat",
)
projection_titles: tuple[str, ...] = Field(
default=Tomo.H5.PROJ_TITLES,
description="Titles to determine if the bliss scan is a set of projection",
alias="proj_titles",
)
alignment_titles: tuple[str, ...] = Field(
default=Tomo.H5.ALIGNMENT_TITLES,
description="Titles to determine if the bliss scan is a set of alignment projection",
)
@field_validator(
"init_titles",
"zseries_init_titles",
"multitomo_init_titles",
"back_and_forth_init_titles",
"dark_titles",
"flat_titles",
"projection_titles",
"alignment_titles",
mode="plain",
)
@classmethod
def cast_entries_or_title_to_tuple(cls, value: str | tuple[str]) -> tuple[str, ...]:
if isinstance(value, str):
value = filter_str_def(value)
return convert_str_to_tuple(value) or ()
[docs] @field_validator(
"entries",
"sub_entries_to_ignore",
mode="before",
)
@classmethod
def cast_entries_or_title_to_tuple_of_url(
cls, value: str | tuple[DataUrl | str, ...]
) -> tuple[DataUrl, ...]:
"""The entries are first converted from a string to a list of string.
Then this list of string will be processed later to create a list of DataUrl with relative link and with a context
"""
if isinstance(value, str):
value = filter_str_def(value)
value = convert_str_to_tuple(value)
entries = EntriesAndTitlesSection.parse_frame_urls(value)
return tuple(
[EntriesAndTitlesSection.fix_entry_name(entry) for entry in entries]
)
[docs] @staticmethod
def parse_frame_urls(urls: tuple[str | DataUrl, ...]):
"""
Insure urls is None or a list of valid DataUrl
"""
if urls in ("", None):
return tuple()
res = []
for i_url, url in enumerate(urls):
if isinstance(url, str):
if url == "":
continue
elif is_url_path(url):
url = DataUrl(path=url)
else:
url = DataUrl(data_path=url, scheme="silx")
if not isinstance(url, DataUrl):
raise ValueError(
"urls tuple should contains DataUrl. "
f"Not {type(url)} at index {i_url}"
)
else:
res.append(url)
return tuple(res)
[docs] @staticmethod
def fix_entry_name(entry: DataUrl):
"""simple util function to insure the entry start by a "/"""
if not isinstance(entry, DataUrl):
raise TypeError("entry is expected to be a DataUrl")
if not entry.data_path().startswith("/"):
entry = DataUrl(
scheme=entry.scheme(),
data_slice=entry.data_slice(),
file_path=entry.file_path(),
data_path="/" + entry.data_path(),
)
return entry