Source code for thoth.common.config.runtime_environment

#!/usr/bin/env python3
# thoth-adviser
# Copyright(C) 2018, 2019 Fridolin Pokorny
#
# This program is free software: you can redistribute it and / or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Representation of runtime environment entry collapsing hardware, runtime and other information."""

import os
import logging
from typing import Optional
from typing import Any
from typing import Dict

import attr
import yaml

from .hardware_information import HardwareInformation
from .operating_system import OperatingSystem

from ..exceptions import ConfigurationError

_LOGGER = logging.getLogger(__name__)


[docs]@attr.s(slots=True) class RuntimeEnvironment: """An entry collapsing configuration options in the user configuration file.""" hardware = attr.ib(type=HardwareInformation) operating_system = attr.ib(type=OperatingSystem) python_version = attr.ib(type=str, default=None) cuda_version = attr.ib(type=str, default=None) name = attr.ib(type=str, default=None) _fully_specified = attr.ib(type=Optional[bool], default=None)
[docs] @classmethod def load(cls, content: Optional[str] = None) -> "RuntimeEnvironment": """Load runtime environment information from file or from a JSON representation, transparently.""" if content is None: return cls.from_dict({}) if os.path.isfile(content): with open(content, "r") as input_file: content = input_file.read() file_content = yaml.safe_load(content) return cls.from_dict(file_content)
[docs] @classmethod def from_dict(cls, dict_: Optional[Dict[Any, Any]] = None) -> "RuntimeEnvironment": """Parse one configuration entry from a dictionary.""" dict_ = dict(dict_ or {}) hardware = dict_.pop("hardware", {}) operating_system = dict_.pop("operating_system", {}) python_version = dict_.pop("python_version", None) cuda_version = dict_.pop("cuda_version", None) name = dict_.pop("name", None) for key, value in dict_.items(): _LOGGER.warning( "Unknown configuration entry in the configuration file %s with value %s", key, value ) instance = cls( hardware=HardwareInformation.from_dict(hardware), # type: ignore operating_system=OperatingSystem.from_dict(operating_system), # type: ignore python_version=python_version, cuda_version=cuda_version, name=name, ) if instance.operating_system.version and not instance.operating_system.name: raise ConfigurationError( "Runtime environment stated operating system version but no operating system name provided" ) return instance
[docs] def to_dict(self, without_none: bool = False) -> Dict[str, Any]: """Convert runtime environment configuration to a dict representation.""" dict_ = attr.asdict(self) # Do not propagate private property. dict_.pop("_fully_specified", None) if not without_none: return dict_ result: Dict[str, Any] = {} for key, value in dict_.items(): # We support one nested configuration entries. if isinstance(value, dict): for k, v in dict_[key].items(): if v is not None: if key not in result: result[key] = {} if k not in result[key]: result[key][k] = {} result[key][k] = v continue if value is not None: result[key] = value return result
[docs] def to_string(self) -> str: """Convert runtime environment configuration to a string representation.""" dict_representation = self.to_dict(without_none=True) return str(dict_representation)
[docs] def is_fully_specified(self) -> bool: """Pre-cache check if the given runtime environment is fully specified.""" if self._fully_specified is None: runtime_environment = ( self.operating_system.name, self.operating_system.version, self.python_version, ) self._fully_specified = all( i is not None for i in runtime_environment ) return self._fully_specified