Source code for mantik.config.validate

import logging
import pathlib
import typing as t

import mantik.config.core as core
import mantik.config.exceptions as exceptions
import mantik.config.executable as executable
import mantik.utils.unicore.upload as upload

[docs] logger = logging.getLogger(__name__)
[docs] class ProjectValidator: def __init__( self, mlproject_path: t.Union[pathlib.Path, str], config: t.Union[pathlib.Path, str, dict], mlflow_parameters: t.Dict, entry_point: str, logger_level: int = logging.WARNING, ):
[docs] self.mlproject_path = pathlib.Path(mlproject_path)
if isinstance(config, dict): self._config = core.Config._from_dict(config) else: self.config_path = pathlib.Path(config)
[docs] self.mlflow_parameters = mlflow_parameters
[docs] self.entry_point = entry_point
logger.setLevel(logger_level) self._config = None @property
[docs] def config(self) -> core.Config: if self._config is None: self._config = core.Config.from_filepath(self.config_absolute_path) return self._config
@property
[docs] def config_absolute_path(self) -> pathlib.Path: return ( self.config_path if self.config_path.is_absolute() else self.mlproject_path / self.config_path )
@property
[docs] def config_relative_path(self) -> pathlib.Path: return ( self.config_path if not self.config_path.is_absolute() else self.config_path.relative_to(self.mlproject_path) )
[docs] def validate(self) -> None: logger.debug( "Validating MLproject at %s and backend config at %s", self.mlproject_path.as_posix(), self.config_absolute_path.as_posix(), ) if not self.mlproject_path.is_absolute(): raise exceptions.ConfigValidationError( "ML project path must be an absolute path, " f"but {self.mlproject_path.as_posix()!r} was given." ) if not self.mlproject_path.is_dir(): raise exceptions.ConfigValidationError( "ML project path not found at " f"{self.mlproject_path.as_posix()!r}, " "check that the given path is correct." ) if not self.config_absolute_path.is_file(): raise exceptions.ConfigValidationError( "Config not found at " f"{self.config_absolute_path.as_posix()!r}, " "check that the given path is correct." ) if not (self.mlproject_path in self.config_absolute_path.parents): raise exceptions.ConfigValidationError( "Config file is not in the ML project directory, " "check that the given paths are correct:\n" f"Config file: {self.config_absolute_path.as_posix()!r}\n" f"ML project directory: {self.mlproject_path.as_posix()!r}" ) if self.config.execution_environment_given(): self._validate_execution_path(self.config.environment.execution) logger.debug("Validating MLproject configuration.") self._validate_ml_project_file() self._validate_config_not_in_exclude()
def _validate_execution_path(self, execution: executable.Execution): if execution.path_has_to_be_checked: execution_absolute_path = self.mlproject_path / execution.path if not execution_absolute_path.is_file(): raise exceptions.ConfigValidationError( f"The path {execution_absolute_path.as_posix()!r} given " "as execution environment was not found, " "check that the given path is correct. " "The path must be relative to the ML project path." ) def _validate_ml_project_file(self) -> None: try: import mlflow except ModuleNotFoundError: logger.warning( ( "Cannot validate MLproject file since mlflow package " "is not installed. Either install the supported version " 'via `pip install "mantik[mlflow]"` or install a ' "desired MLflow version manually." ), exc_info=True, ) else: mlflow.projects.utils.fetch_and_validate_project( uri=self.mlproject_path.as_posix(), version=None, entry_point=self.entry_point, parameters=self.mlflow_parameters, ) def _validate_config_not_in_exclude(self) -> None: if upload.file_matches_exclude_pattern( path=self.config_absolute_path, project_dir=self.mlproject_path, exclude=self.config.files_to_exclude, ): raise exceptions.ConfigValidationError( f"Config file '{self.config_path.name}' cannot be excluded, " f"check config 'Exclude' section" )