Source code for aiida.manage.configuration.options
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved. #
# This file is part of the AiiDA code. #
# #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida-core #
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
"""Definition of known configuration options and methods to parse and get option values."""
from typing import Any, Dict, List, Tuple
from aiida.common.exceptions import ConfigurationError
__all__ = ('get_option', 'get_option_names', 'parse_option', 'Option')
[docs]
class Option:
"""Represent a configuration option schema."""
[docs]
def __init__(self, name: str, schema: Dict[str, Any], field):
self._name = name
self._schema = schema
self._field = field
[docs]
def __str__(self) -> str:
return f'Option(name={self._name})'
@property
def name(self) -> str:
return self._name
@property
def valid_type(self) -> Any:
return self._field.annotation
@property
def schema(self) -> Dict[str, Any]:
return self._schema
@property
def default(self) -> Any:
return self._field.default
@property
def description(self) -> str:
return self._field.description
@property
def global_only(self) -> bool:
from .config import ProfileOptionsSchema
return self._name.replace('.', '__') not in ProfileOptionsSchema.model_fields
[docs]
def validate(self, value: Any) -> Any:
"""Validate a value
:param value: The input value
:return: The output value
:raise: ConfigurationError
"""
from pydantic import ValidationError
from .config import GlobalOptionsSchema
attribute = self.name.replace('.', '__')
try:
# There is no straightforward way to validate a single field of a model in pydantic v2.0. The following
# approach is the current work around, see: https://github.com/pydantic/pydantic/discussions/7367
result = GlobalOptionsSchema.__pydantic_validator__.validate_assignment(
GlobalOptionsSchema.model_construct(), attribute, value
)
except ValidationError as exception:
messages = []
for error in exception.errors():
try:
messages.append(str(error['ctx']['error']))
except KeyError:
messages.append(f"Invalid value for `{error['loc'][0]}`: {error['msg']}")
raise ConfigurationError('\n'.join(messages)) from exception
# Return the value from the constructed model as this will have casted the value to the right type
return getattr(result, attribute)
[docs]
def get_option_names() -> List[str]:
"""Return a list of available option names."""
from .config import GlobalOptionsSchema
return [key.replace('__', '.') for key in GlobalOptionsSchema.model_fields]
[docs]
def get_option(name: str) -> Option:
"""Return option."""
from .config import GlobalOptionsSchema
options = GlobalOptionsSchema.model_fields
option_name = name.replace('.', '__')
if option_name not in options:
raise ConfigurationError(f'the option {name} does not exist')
return Option(name, GlobalOptionsSchema.model_json_schema()['properties'][option_name], options[option_name])
[docs]
def parse_option(option_name: str, option_value: Any) -> Tuple[Option, Any]:
"""Parse and validate a value for a configuration option.
:param option_name: the name of the configuration option
:param option_value: the option value
:return: a tuple of the option and the parsed value
"""
option = get_option(option_name)
value = option.validate(option_value)
return option, value