Source code for ocebuild.errors.validation

#pragma no-implicit

## @file
# Copyright (c) 2023, The OCE Build Authors. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
##
"""Validation methods used for testing and at runtime."""

#pylint: disable=cell-var-from-loop

from contextlib import suppress
from functools import partial
from os import PathLike

from typing import Callable, Literal, Optional, Tuple, Union

from ._lib import disable_exception_traceback
from .types import PathValidationError

from ocebuild.parsers.dict import flatten_dict

#NOTE: This import was remapped from 'third_party' to 'ocebuild.third_party'.
from ocebuild.third_party.cpython.pathlib import Path


[docs]def validate(call: Callable[[], bool], err: Union[Exception, Callable[[Tuple[any, ...]], Exception]], msg: Optional[str] ) -> None: """Throws a ValidationError with the given message.""" result: bool=True # Override AssertionError context with ValidationError with suppress(AssertionError): result=call() if not result: with disable_exception_traceback(): raise err(msg if msg else f'Failed {call.__name__} validation test')
[docs]def validate_path_tree(path: Union[str, "PathLike[str]"], tree: dict, delimiter: str='/' ) -> Literal[True]: """Validates a given path matches a tree schema. Args: path: The path to validate. tree: The tree schema to validate against. delimiter: The delimiter to use when flattening the tree. Raises: PathValidationError: If the path does not match the tree schema. Returns: True if the path matches the tree schema. """ # Verify path exists root_dir = Path(path) for ftree, flag in flatten_dict(tree, delimiter).items(): # Create error partial for re-use absolute_path = root_dir.joinpath(*ftree.split('/')) name = absolute_path.name path = str(absolute_path)[len(str(root_dir))+1:] kind = 'file' if flag in ('f', 'file') else 'directory' err = partial(PathValidationError, name=name, kind=kind, path=path) # Verify path exists def path_exists() -> bool: return absolute_path.exists() validate(path_exists, err, msg=f"Missing {kind} '{name}' (at {path})") # Handle flags if flag == '*': # Verify subdirectory is populated def is_populated() -> bool: return bool(set(absolute_path.iterdir())) validate(is_populated, err, msg=f"Path '{name}' is empty (at {path})") elif flag in ('f', 'file', 'd', 'dir'): # Verify path type matches flag def is_type() -> bool: if kind == 'file': # Verify path points to a file return absolute_path.is_file() elif kind == 'directory': # Verify path points to a directory return absolute_path.is_dir() else: raise ValueError('Invalid path type given') validate(is_type, err, msg=f"Path '{name}' not a {kind} (at {path})") # Invalid flag else: raise ValueError(f"Invalid flag '{flag}' given for path '{name}' (at {path})") return True
__all__ = [ # Functions (2) "validate", "validate_path_tree" ]