Package configurator

Expand source code
from configurator.main import BaseSettings, SettingsError
from configurator.fields import *

__all__ = [
    'BaseSettings',
    'SettingsError',
    'Integer',
    'PositiveInteger',
    'String',
    'Email',
    'Boolean',
    'Float',
    'Url',
    'ValidationError'
]

Sub-modules

configurator.fields

Settings fields

configurator.main

Settings class implementation

configurator.utils

Commonly used sets of settings.

Classes

class BaseSettings (*args, **kwargs)

Base Settings model. All user's settings classes should be subclass of it.

Creates a new Settings object.

Args

args: *kwargs:

Expand source code
class BaseSettings(Field, metaclass=SettingsMeta):
    """
    Base Settings model.
    All user's settings classes should be subclass of it.
    """
    _type = dict

    # Populated by the metaclass, defined here to help IDEs only
    _fields = {}

    def __init__(self, *args, **kwargs):
        """
        Creates a new Settings object.
        Args:
            *args:
            **kwargs:
        """
        super().__init__(*args, **kwargs)
        self.__data = {}
        for k, v in self._fields.items():
            # Embedded settings objects are stored in __data
            if isinstance(v, BaseSettings):
                self.__data[k] = deepcopy(v)
            else:
                self.__data[k] = v.default

    def from_json(self, filename: str) -> None:
        """
        Loads config from json file.
        Args:
            filename: path to json file
        """
        with open(filename) as json_file:
            data = json.load(json_file)
            self.from_dict(data)

    def to_json(self, filename: str) -> None:
        """
        Saves current settings to json file.
        Method can be used on a new object to generate template json.
        Args:
            filename: path to json file
        """
        with open(filename, 'w') as outfile:
            json.dump(self.to_dict(), outfile, indent=4)

    def from_yaml(self, filename: str) -> None:
        """
        Loads config from yaml file.
        Args:
            filename: path to yaml file
        """
        with open(filename) as yaml_file:
            data = yaml.safe_load(yaml_file)
            self.from_dict(data)

    def to_yaml(self, filename: str) -> None:
        """
        Saves current settings to yaml file.
        Method can be used on a new object to generate template yaml.
        Args:
            filename: path to yaml file
        """
        with open(filename, 'w') as outfile:
            yaml.dump(self.to_dict(), outfile)

    def from_dict(self, data: dict, partial_update: bool = False) -> None:
        """
        Updates settings with provided dict.
        All required settings should be present in the dict unless partial_update is True.
        Args:
            data: dictionary with new settings
            partial_update: set True if you don't want to update all required settings
        """
        for k, v in self._fields.items():
            value = data.get(k)
            if value is not None:
                try:
                    value = v.validate(value)
                except ValidationError as ex:
                    raise SettingsError(
                        f'Value {value} for field "{k}" did not pass validation checks: {ex}'
                    ) from ex
                if isinstance(v, BaseSettings):
                    self.__data[k].from_dict(value)
                else:
                    self.__data[k] = value
            else:
                if v.required and not partial_update:
                    raise SettingsError(f'Missing required value: {k}')

    def to_dict(self) -> dict:
        """
        Returns settings in dictionary format.
        Returns:
            dictionary with all the settings as primitive types.
        """
        return {k: (v if not isinstance(v, BaseSettings) else v.to_dict()) for k, v in self.__data.items()}

    def __getattr__(self, name: str) -> Any:
        if name in self._fields:
            return self.__data.get(name)
        else:
            raise AttributeError

    def __setattr__(self, name: str, value: Any) -> Any:
        if name in self._fields:
            if isinstance(self._fields[name], BaseSettings):
                raise AttributeError('Overriding Settings objects is not allowed, use from_dict() method.')
            self.__data[name] = self._fields[name].validate(value)
        else:
            super().__setattr__(name, value)

Ancestors

Subclasses

Methods

def from_dict(self, data: dict, partial_update: bool = False) ‑> None

Updates settings with provided dict. All required settings should be present in the dict unless partial_update is True.

Args

data
dictionary with new settings
partial_update
set True if you don't want to update all required settings
Expand source code
def from_dict(self, data: dict, partial_update: bool = False) -> None:
    """
    Updates settings with provided dict.
    All required settings should be present in the dict unless partial_update is True.
    Args:
        data: dictionary with new settings
        partial_update: set True if you don't want to update all required settings
    """
    for k, v in self._fields.items():
        value = data.get(k)
        if value is not None:
            try:
                value = v.validate(value)
            except ValidationError as ex:
                raise SettingsError(
                    f'Value {value} for field "{k}" did not pass validation checks: {ex}'
                ) from ex
            if isinstance(v, BaseSettings):
                self.__data[k].from_dict(value)
            else:
                self.__data[k] = value
        else:
            if v.required and not partial_update:
                raise SettingsError(f'Missing required value: {k}')
def from_json(self, filename: str) ‑> None

Loads config from json file.

Args

filename
path to json file
Expand source code
def from_json(self, filename: str) -> None:
    """
    Loads config from json file.
    Args:
        filename: path to json file
    """
    with open(filename) as json_file:
        data = json.load(json_file)
        self.from_dict(data)
def from_yaml(self, filename: str) ‑> None

Loads config from yaml file.

Args

filename
path to yaml file
Expand source code
def from_yaml(self, filename: str) -> None:
    """
    Loads config from yaml file.
    Args:
        filename: path to yaml file
    """
    with open(filename) as yaml_file:
        data = yaml.safe_load(yaml_file)
        self.from_dict(data)
def to_dict(self) ‑> dict

Returns settings in dictionary format.

Returns

dictionary with all the settings as primitive types.

Expand source code
def to_dict(self) -> dict:
    """
    Returns settings in dictionary format.
    Returns:
        dictionary with all the settings as primitive types.
    """
    return {k: (v if not isinstance(v, BaseSettings) else v.to_dict()) for k, v in self.__data.items()}
def to_json(self, filename: str) ‑> None

Saves current settings to json file. Method can be used on a new object to generate template json.

Args

filename
path to json file
Expand source code
def to_json(self, filename: str) -> None:
    """
    Saves current settings to json file.
    Method can be used on a new object to generate template json.
    Args:
        filename: path to json file
    """
    with open(filename, 'w') as outfile:
        json.dump(self.to_dict(), outfile, indent=4)
def to_yaml(self, filename: str) ‑> None

Saves current settings to yaml file. Method can be used on a new object to generate template yaml.

Args

filename
path to yaml file
Expand source code
def to_yaml(self, filename: str) -> None:
    """
    Saves current settings to yaml file.
    Method can be used on a new object to generate template yaml.
    Args:
        filename: path to yaml file
    """
    with open(filename, 'w') as outfile:
        yaml.dump(self.to_dict(), outfile)

Inherited members

class Boolean (required: bool = True, default: Any = None)

Class for bool type fields.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class Boolean(Field):
    """
    Class for bool type fields.
    """
    type_ = bool
    default = False

Ancestors

Class variables

var default : Any

Inherited members

class Email (required: bool = True, default: Any = None)

Class for email fields.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class Email(String):
    """
    Class for email fields.
    """

    def validate(self, value: str) -> str:
        """Validates email using simple regex."""
        value = super().validate(value)
        regex = re.compile(r'^\S+@\S+\.\S+$')
        if regex.fullmatch(value) is None:
            raise ValidationError('Provided string is not a valid email.')
        return value

Ancestors

Methods

def validate(self, value: str) ‑> str

Validates email using simple regex.

Expand source code
def validate(self, value: str) -> str:
    """Validates email using simple regex."""
    value = super().validate(value)
    regex = re.compile(r'^\S+@\S+\.\S+$')
    if regex.fullmatch(value) is None:
        raise ValidationError('Provided string is not a valid email.')
    return value

Inherited members

class Float (required: bool = True, default: Any = None)

Class for floating-point numbers.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class Float(Field):
    """
    Class for floating-point numbers.
    """
    type_ = float
    default = 0.0

Ancestors

Class variables

var default : Any

Inherited members

class Integer (required: bool = True, default: Any = None)

Class for number type fields.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class Integer(Field):
    """
    Class for number type fields.
    """
    type_ = int
    default = 0

Ancestors

Subclasses

Class variables

var default : Any

Inherited members

class PositiveInteger (required: bool = True, default: Any = None)

Class for positive integers - natural numbers.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class PositiveInteger(Integer):
    """
    Class for positive integers - natural numbers.
    """
    default = 1

    def validate(self, value: int) -> int:
        value = super().validate(value)
        if value <= 0:
            raise ValidationError('PositiveInteger value must be greater than 0.')
        return value

Ancestors

Class variables

var default : Any

Inherited members

class SettingsError (*args, **kwargs)

Thrown when Settings object is used incorrectly, i.e. required parameters are missing in config json

Expand source code
class SettingsError(Exception):
    """
    Thrown when Settings object is used incorrectly,
    i.e. required parameters are missing in config json
    """

Ancestors

  • builtins.Exception
  • builtins.BaseException
class String (required: bool = True, default: Any = None)

Class for string type fields.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class String(Field):
    """
    Class for string type fields.
    """
    type_ = str
    default = ''

Ancestors

Subclasses

Class variables

var default : Any

Inherited members

class Url (required: bool = True, default: Any = None)

Class for url fields.

Creates new Field object.

Args

required
set true if field is crucial for the project and should be always provided
default
default field value if not specified in config
Expand source code
class Url(String):
    """
    Class for url fields.
    """

    def validate(self, value: str) -> str:
        """Validates url using regular expression."""
        value = super().validate(value)
        regex = regex = re.compile(
            r'^https?://'  # http:// or https://
            r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'  # domain...
            r'localhost|'  # localhost...
            r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
            r'(?::\d+)?'  # optional port
            r'(?:/?|[/?]\S+)$', re.IGNORECASE)
        if regex.fullmatch(value) is None:
            raise ValidationError('Provided string is not a valid url.')
        return value

Ancestors

Methods

def validate(self, value: str) ‑> str

Validates url using regular expression.

Expand source code
def validate(self, value: str) -> str:
    """Validates url using regular expression."""
    value = super().validate(value)
    regex = regex = re.compile(
        r'^https?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'  # domain...
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
    if regex.fullmatch(value) is None:
        raise ValidationError('Provided string is not a valid url.')
    return value

Inherited members

class ValidationError (*args, **kwargs)

Thrown when value for the Field didn't pass the validation.

Expand source code
class ValidationError(Exception):
    """
    Thrown when value for the Field didn't pass the validation.
    """

Ancestors

  • builtins.Exception
  • builtins.BaseException