Skip to content

Api

BaseModel and FileModel

Here we define our Pydantic BaseModel with custom settings, as well as a FileModel that inherits from a BaseModel but also represents a file on disk.

BaseModel (BaseModel) pydantic-model

__init__(self, **data: Any) -> None special

Initializes a BaseModel with the provided data.

Exceptions:

Type Description
ValidationError

A validation error when the data is invalid.

Source code in hydrolib/core/basemodel.py
def __init__(self, **data: Any) -> None:
    """Initializes a BaseModel with the provided data.

    Raises:
        ValidationError: A validation error when the data is invalid.
    """
    try:
        super().__init__(**data)
    except ValidationError as e:
        id = self._get_identifier(data)
        if id is None:
            raise e
        else:
            # If there is an identifier, include this in the ValidationError messages.
            raise ValidationError([ErrorWrapper(e, loc=id)], self.__class__)

Generic attribute for models backed by a file.

Source code in hydrolib/core/basemodel.py
def is_file_link(self) -> bool:
    """Generic attribute for models backed by a file."""
    return False

Generic attribute for models that have children fields that could contain files.

Source code in hydrolib/core/basemodel.py
def is_intermediate_link(self) -> bool:
    """Generic attribute for models that have children fields that could contain files."""
    return self.is_file_link()

show_tree(self, indent = 0)

Recursive print function for showing a tree of a model.

Source code in hydrolib/core/basemodel.py
def show_tree(self, indent=0):
    """Recursive print function for showing a tree of a model."""
    angle = "∟" if indent > 0 else ""

    # Only print if we're backed by a file
    if self.is_file_link():
        print(" " * indent * 2, angle, self)

    # Otherwise we recurse through the fields of a model
    for _, value in self:
        # Handle lists of items
        if not isinstance(value, list):
            value = [value]
        for v in value:
            if hasattr(v, "is_intermediate_link") and v.is_intermediate_link():
                # If the field is only an intermediate, print the name only
                if not v.is_file_link():
                    print(" " * (indent * 2 + 2), angle, v.__class__.__name__)
                v.show_tree(indent + 1)

FileModel (BaseModel, ABC) pydantic-model

Base class to represent models with a file representation.

It therefore always has a filepath and if it is given on initilization, it will parse that file.

This class extends the validate option of Pydantic, so when when a Path is given to a field with type FileModel, it doesn't error, but actually initializes the FileModel.

__init__(self, filepath: Optional[pathlib.Path] = None, *args, **kwargs) special

Initialize a model.

The model is empty (with defaults) if no filepath is given, otherwise the file at filepath will be parsed.

Source code in hydrolib/core/basemodel.py
def __init__(self, filepath: Optional[Path] = None, *args, **kwargs):
    """Initialize a model.

    The model is empty (with defaults) if no `filepath` is given,
    otherwise the file at `filepath` will be parsed."""
    # Parse the file if path is given
    context_dir_reset_token = None
    if filepath:
        filepath = Path(filepath)  # so we also accept strings

        if filepath in FileModel._file_models_cache:
            return None

        # If not set, this is the root file path
        if not context_dir.get(None):
            logger.info(f"Set context to {filepath.parent}")
            context_dir_reset_token = context_dir.set(filepath.parent)

        FileModel._file_models_cache[filepath] = self

        logger.info(f"Loading data from {filepath}")
        data = self._load(filepath)
        data["filepath"] = filepath
        kwargs.update(data)

    try:
        super().__init__(*args, **kwargs)
    finally:
        _reset_context_dir(context_dir_reset_token)

__new__(cls, filepath: Optional[pathlib.Path] = None, *args, **kwargs) special staticmethod

Creates a new model. If the file at the provided file path was already parsed, this instance is returned.

Parameters:

Name Type Description Default
filepath Optional[Path]

The absolute file path to the file. Defaults to None.

None

Returns:

Type Description
FileModel

A file model.

Source code in hydrolib/core/basemodel.py
def __new__(cls, filepath: Optional[Path] = None, *args, **kwargs):
    """Creates a new model.
    If the file at the provided file path was already parsed, this instance is returned.

    Args:
        filepath (Optional[Path], optional): The absolute file path to the file. Defaults to None.

    Returns:
        FileModel: A file model.
    """

    if filepath:
        filepath = Path(filepath)

        if filepath in FileModel._file_models_cache:
            filemodel = FileModel._file_models_cache[filepath]
            logger.info(
                f"Returning existing {type(filemodel).__name__} from cache, because {filepath} was already parsed."
            )
            return filemodel

    return super().__new__(cls)

__str__(self) -> str special

Return str(self).

Source code in hydrolib/core/basemodel.py
def __str__(self) -> str:
    return str(self.filepath if self.filepath else "")

Generic attribute for models backed by a file.

Source code in hydrolib/core/basemodel.py
def is_file_link(self) -> bool:
    return True

save(self, folder: Optional[pathlib.Path] = None) -> Path

Save model and child models to their set filepaths.

If a folder is given, for models with an unset filepath, we generate one based on the given folder and a default name. Otherwise we override the folder part of already set filepaths. This can thus be used to copy complete models.

Parameters:

Name Type Description Default
folder Optional[pathlib.Path]

path to the folder where this FileModel will be stored

None
Source code in hydrolib/core/basemodel.py
def save(self, folder: Optional[Path] = None) -> Path:
    """Save model and child models to their set filepaths.

    If a folder is given, for models with an unset filepath,
    we generate one based on the given `folder` and a default name.
    Otherwise we override the folder part of already set filepaths.
    This can thus be used to copy complete models.

    Args:
        folder: path to the folder where this FileModel will be stored
    """
    if not self.filepath and not folder:
        raise ValueError(
            "Either set the `filepath` on the model or pass a `folder` when saving."
        )

    if not folder:
        folder = self.filepath.absolute().parent

    self._apply_recurse("_save", folder)
    return self.filepath.absolute()
Back to top