Source code for coalib.settings.Setting

import os
from collections import Iterable, OrderedDict

from coala_utils.decorators import (
    enforce_signature,
    generate_repr,
)
from coala_utils.string_processing.StringConverter import StringConverter
from coalib.bearlib.languages.Language import Language, UnknownLanguageError
from coalib.parsing.Globbing import glob_escape


[docs]def path(obj, *args, **kwargs): return obj.__path__(*args, **kwargs)
[docs]def path_list(obj, *args, **kwargs): return obj.__path_list__(*args, **kwargs)
[docs]def url(obj, *args, **kwargs): return obj.__url__(*args, **kwargs)
[docs]def glob(obj, *args, **kwargs): """ Creates a path in which all special glob characters in all the parent directories in the given setting are properly escaped. :param obj: The ``Setting`` object from which the key is obtained. :return: Returns a path in which special glob characters are escaped. """ return obj.__glob__(*args, **kwargs)
[docs]def glob_list(obj, *args, **kwargs): """ Creates a list of paths in which all special glob characters in all the parent directories of all paths in the given setting are properly escaped. :param obj: The ``Setting`` object from which the key is obtained. :return: Returns a list of paths in which special glob characters are escaped. """ return obj.__glob_list__(*args, **kwargs)
[docs]def language(name): """ Convert a string into ``Language`` object. :param name: String containing language name. :return: ``Language`` object. :raises ValueError: If the ``name`` contain invalid language name. """ try: return Language[name] except UnknownLanguageError as e: raise ValueError(e)
[docs]def typed_list(conversion_func): """ Creates a class that converts a setting into a list of elements each converted with the given conversion function. :param conversion_func: The conversion function that converts a string into your desired list item object. :return: An instance of the created conversion class. """ class Converter: def __call__(self, setting): return [conversion_func(StringConverter(elem)) for elem in setting] def __repr__(self): return 'typed_list(%s)' % conversion_func.__name__ return Converter()
str_list = typed_list(str) int_list = typed_list(int) float_list = typed_list(float) bool_list = typed_list(bool)
[docs]def typed_dict(key_type, value_type, default): """ Creates a class that converts a setting into a dict with the given types. :param key_type: The type conversion function for the keys. :param value_type: The type conversion function for the values. :param default: The default value to use if no one is given by the user. :return: An instance of the created conversion class. """ class Converter: def __call__(self, setting): return {key_type(StringConverter(key)): value_type(StringConverter(value)) if value != '' else default for key, value in dict(setting).items()} def __repr__(self): return 'typed_dict(%s, %s, default=%s)' % ( key_type.__name__, value_type.__name__, default) return Converter()
[docs]def typed_ordered_dict(key_type, value_type, default): """ Creates a class that converts a setting into an ordered dict with the given types. :param key_type: The type conversion function for the keys. :param value_type: The type conversion function for the values. :param default: The default value to use if no one is given by the user. :return: An instance of the created conversion class. """ class Converter: def __call__(self, setting): return OrderedDict((key_type(StringConverter(key)), value_type(StringConverter(value)) if value != '' else default) for key, value in OrderedDict(setting).items()) def __repr__(self): return 'typed_ordered_dict(%s, %s, default=%s)' % ( key_type.__name__, value_type.__name__, default) return Converter()
[docs]@generate_repr('key', 'value', 'origin', 'from_cli', 'to_append') class Setting(StringConverter): """ A Setting consists mainly of a key and a value. It mainly offers many conversions into common data types. """ @enforce_signature def __init__(self, key, value, origin: str = '', strip_whitespaces: bool = True, list_delimiters: Iterable = (',', ';'), from_cli: bool = False, remove_empty_iter_elements: bool = True, to_append: bool = False): """ Initializes a new Setting, :param key: The key of the Setting. :param value: The value, if you apply conversions to this object these will be applied to this value. :param origin: The originating file. This will be used for path conversions and the last part will be stripped of. If you want to specify a directory as origin be sure to end it with a directory separator. :param strip_whitespaces: Whether to strip whitespaces from the value or not :param list_delimiters: Delimiters for list conversion :param from_cli: True if this setting was read by the CliParser. :param remove_empty_iter_elements: Whether to remove empty elements in iterable values. :param to_append: The boolean value if setting value needs to be appended to a setting in the defaults of a section. """ self.to_append = to_append StringConverter.__init__( self, value, strip_whitespaces=strip_whitespaces, list_delimiters=list_delimiters, remove_empty_iter_elements=remove_empty_iter_elements) self.from_cli = from_cli self.key = key self.origin = str(origin) def __path__(self, origin=None, glob_escape_origin=False): """ Determines the path of this setting. Note: You can also use this function on strings, in that case the origin argument will be taken in every case. :param origin: The origin file to take if no origin is specified for the given setting. If you want to provide a directory, make sure it ends with a directory separator. :param glob_escape_origin: When this is set to true, the origin of this setting will be escaped with ``glob_escape``. :return: An absolute path. :raises ValueError: If no origin is specified in the setting nor the given origin parameter. """ strrep = str(self).strip() if os.path.isabs(strrep): return strrep if hasattr(self, 'origin') and self.origin != '': origin = self.origin if origin is None: raise ValueError('Cannot determine path without origin.') # We need to get full path before escaping since the full path # may introduce unintended glob characters origin = os.path.abspath(os.path.dirname(origin)) if glob_escape_origin: origin = glob_escape(origin) return os.path.normpath(os.path.join(origin, strrep)) def __glob__(self, origin=None): """ Determines the path of this setting with proper escaping of its parent directories. :param origin: The origin file to take if no origin is specified for the given setting. If you want to provide a directory, make sure it ends with a directory separator. :return: An absolute path in which the parent directories are escaped. :raises ValueError: If no origin is specified in the setting nor the given origin parameter. """ return Setting.__path__(self, origin, glob_escape_origin=True) def __path_list__(self): """ Splits the value into a list and creates a path out of each item taking the origin of the setting into account. :return: A list of absolute paths. """ return [Setting.__path__(elem, self.origin) for elem in self] def __glob_list__(self): """ Splits the value into a list and creates a path out of each item in which the special glob characters in origin are escaped. :return: A list of absolute paths in which the special characters in the parent directories of the setting are escaped. """ return [Setting.__glob__(elem, self.origin) for elem in self] def __iter__(self, remove_backslashes=True): if self.to_append: raise ValueError('Iteration on this object is invalid because the ' 'value is incomplete. Please access the value of ' 'the setting in a section to iterate through it.') return StringConverter.__iter__(self, remove_backslashes) @property def key(self): return self._key @key.setter def key(self, key): newkey = str(key) if newkey == '': raise ValueError('An empty key is not allowed for a setting.') self._key = newkey @StringConverter.value.getter def value(self): if self.to_append: raise ValueError('This property is invalid because the value is ' 'incomplete. Please access the value of the ' 'setting in a section to get the complete value.') return self._value