Skip to content

Module API - Fields

superconf.fields

Fields management

Field

Base class for configuration fields.

A Field represents a single configuration value with optional type casting, default values, and help text. Fields are used as descriptors in configuration classes to define the structure and behavior of configuration values.

Attributes:

Name Type Description
cast

The casting function to use for converting raw values. If None, will be determined based on the default value's type.

Source code in superconf/fields.py
class Field:
    """Base class for configuration fields.

    A Field represents a single configuration value with optional type casting,
    default values, and help text. Fields are used as descriptors in configuration
    classes to define the structure and behavior of configuration values.

    Attributes:
        cast: The casting function to use for converting raw values. If None,
            will be determined based on the default value's type.
    """

    cast = None

    # pylint: disable=redefined-builtin
    def __init__(
        self,
        key: str = None,
        *,
        help: str = "",
        default=NOT_SET,
        cast: Callable = None,
    ):
        """Initialize a new Field instance.

        Args:
            key: Name of the value used in file or environment variable.
                Set automatically by the metaclass.
            help: Plain-text description of the value.
            default: Default value if none is provided. If left unset,
                loading a config that fails to provide this value
                will raise a UnknownConfiguration exception.
            cast: Callable to cast variable with. Defaults to type of
                default (if provided), identity if default is not
                provided or raises TypeError if provided cast is not
                callable.
        """
        self.key = key
        self.help = help
        self.default = default
        self.cast = cast or self.cast

    def __get__(self, conf_instance, owner):
        """Descriptor get method to retrieve the field's value.

        Args:
            conf_instance: The configuration instance this field belongs to.
            owner: The class that owns this descriptor.

        Returns:
            The field's value if accessed through an instance,
            or the field itself if accessed through the class.
        """
        if conf_instance:
            return conf_instance.get_field_value(key=self.key, field=self)
        return self

    def __repr__(self):
        """Return a string representation of the field.

        Returns:
            A string showing the field's class name, key, and help text.
        """
        return f'{self.__class__.__name__}(key="{self.key}", help="{self.help}")'

    def is_container(self):
        """Check if this field is a container type.

        Returns:
            bool: True if this field has a children_class attribute,
            indicating it can contain nested configuration values.
        """
        children_class = getattr(self, "children_class", None)
        if children_class is not None:
            return True
        return False

    # pylint: disable=too-many-locals, too-many-branches, too-many-arguments, too-many-statements, too-many-positional-arguments
    def resolve_value(
        self,
        conf_instance,
        value=NOT_SET,
        default=NOT_SET,
        cast=NOT_SET,
        loaders=NOT_SET,
        lookup=True,
        **kwargs,
    ):
        """Resolve the final value for this field.

        This method handles the complex logic of determining the field's value by:
        1. Checking for explicitly provided values
        2. Looking up values through loaders
        3. Falling back to defaults
        4. Applying type casting

        Args:
            conf_instance: The configuration instance this field belongs to.
            value: Explicitly provided value, takes precedence if set.
            default: Override for the field's default value.
            cast: Override for the field's cast function.
            loaders: List of loader objects to use for value lookup.
            lookup: Enable loaders, or only use _value instead.
            **kwargs: Additional keyword arguments passed to loaders.

        Returns:
            tuple: A tuple containing:
                - The resolved and cast value
                - A SimpleNamespace containing metadata about the resolution process

        Raises:
            CastValueFailure: If strict casting is enabled and the value
                cannot be cast to the desired type.
        """
        key = self.key
        assert isinstance(key, (str, int)), f"Got: {type(key)} {key}"

        # Process defaults
        default_from = ["args"]
        if default is NOT_SET and isinstance(conf_instance._default, dict):
            # Fetch default from container

            # default2 = default
            try:
                default = conf_instance.query_inst_cfg(
                    "default", override=kwargs, default=NOT_SET
                )[key]
                default_from.append("conf_instance_query")
            except KeyError:
                pass

        if default is NOT_SET:
            # Fetch default from field
            default = self.default
            default_from.append("field_instance")

        # Process value
        if value is NOT_SET:
            # Fetch default from container
            try:
                value = conf_instance._value[key]
            except (TypeError, KeyError):  # For dict
                pass
            except IndexError:  # For list
                pass

        # Process cast
        cast_from = []
        if cast is NOT_SET:
            cast = self.cast
            cast_from.append(f"field_attr:{self}.cast")
        if cast is NOT_SET:
            cast = conf_instance._cast
            cast_from.append(f"conf_attr:{conf_instance}._cast")

        # Process loaders
        if not lookup:
            loaders = [_Value({key: value})]
        else:
            if loaders is NOT_SET:
                loaders = conf_instance._loaders
            if value:
                # pylint: disable=using-constant-test
                if False:
                    loaders.insert(0, _Value({key: value}))
                else:
                    # Remove any existing _Value
                    loaders = [
                        loader for loader in loaders if not isinstance(loader, _Value)
                    ]
                    loaders.append(_Value({key: value}))

        # Determine cast method
        if callable(cast):
            # cast = cast
            cast_from.append("cast_is_callable")
        elif cast is None and (default is NOT_SET or default is None):
            cast = as_is
            cast_from.append("cast_is_none_and_no_defaults")
        elif isinstance(default, bool):
            cast = as_boolean
            cast_from.append("cast_as_boolean")
        elif cast is None:
            cast = type(default)
            cast_from.append("cast_is_none")
        elif cast is NOT_SET:
            if default is NOT_SET or default is None:
                cast_from.append("cast_notset_type_default")
                cast = type(default)
            else:
                cast_from.append("cast_notset_type_as_is")
                cast = as_is
        else:
            raise TypeError(f"Cast must be callable, got: {type(cast)}")

        # Process things
        is_casted = False
        result = NOT_SET
        loader_from = []
        results_from = []
        # print(f"ACTUAL LOADERS FOR {self}", loaders)
        logger.debug("Current loaders for %s: %s", self, loaders)
        for loader in loaders:
            loader_from.append(str(loader))
            try:
                logger.debug("Try loader for %s.%s: %s", self, key, loaders)
                # print(f"  > LOADER: try search in {loader} key: {key}")
                # print("VS", self, conf_instance)
                result = loader.getitem(conf_instance, key, **kwargs)

            except KeyError:
                continue

            if result is not NOT_SET:
                results_from.append(f"from_loader:{loader}")
                result = cast(result)
                is_casted = True
                break

        # Nothing found in all loaders, then fallback on default
        if result is NOT_SET:
            result = value
            results_from.append("from_value")
        if result is NOT_SET:
            result = default
            results_from.append("from_default")

        # Try to cast value
        if not is_casted:
            error = None
            try:
                result = cast(result)
                results_from.append(f"casted:{cast}")
            except (exceptions.InvalidCastConfiguration, ValueError, TypeError) as err:
                error = err
                result = NOT_SET
                results_from.append(f"not_castable:{cast}")

            # Check for strict_cast mode:
            if error is not None and conf_instance._strict_cast is True:
                msg = (
                    f"Got error {conf_instance}.{key} {type(error)}: {error}, "
                    "set strict_cast=False to disable this error"
                )
                raise exceptions.CastValueFailure(msg)

        meta = SimpleNamespace(
            cast=cast,
            default=default,
            loaders=loaders,
            value=result,
            cast_from=cast_from,
            loader_from=loader_from,
            results_from=results_from,
            default_from=default_from,
        )

        return result, meta

__get__(conf_instance, owner)

Descriptor get method to retrieve the field's value.

Parameters:

Name Type Description Default
conf_instance

The configuration instance this field belongs to.

required
owner

The class that owns this descriptor.

required

Returns:

Type Description

The field's value if accessed through an instance,

or the field itself if accessed through the class.

Source code in superconf/fields.py
def __get__(self, conf_instance, owner):
    """Descriptor get method to retrieve the field's value.

    Args:
        conf_instance: The configuration instance this field belongs to.
        owner: The class that owns this descriptor.

    Returns:
        The field's value if accessed through an instance,
        or the field itself if accessed through the class.
    """
    if conf_instance:
        return conf_instance.get_field_value(key=self.key, field=self)
    return self

__init__(key=None, *, help='', default=NOT_SET, cast=None)

Initialize a new Field instance.

Parameters:

Name Type Description Default
key str

Name of the value used in file or environment variable. Set automatically by the metaclass.

None
help str

Plain-text description of the value.

''
default

Default value if none is provided. If left unset, loading a config that fails to provide this value will raise a UnknownConfiguration exception.

NOT_SET
cast Callable

Callable to cast variable with. Defaults to type of default (if provided), identity if default is not provided or raises TypeError if provided cast is not callable.

None
Source code in superconf/fields.py
def __init__(
    self,
    key: str = None,
    *,
    help: str = "",
    default=NOT_SET,
    cast: Callable = None,
):
    """Initialize a new Field instance.

    Args:
        key: Name of the value used in file or environment variable.
            Set automatically by the metaclass.
        help: Plain-text description of the value.
        default: Default value if none is provided. If left unset,
            loading a config that fails to provide this value
            will raise a UnknownConfiguration exception.
        cast: Callable to cast variable with. Defaults to type of
            default (if provided), identity if default is not
            provided or raises TypeError if provided cast is not
            callable.
    """
    self.key = key
    self.help = help
    self.default = default
    self.cast = cast or self.cast

__repr__()

Return a string representation of the field.

Returns:

Type Description

A string showing the field's class name, key, and help text.

Source code in superconf/fields.py
def __repr__(self):
    """Return a string representation of the field.

    Returns:
        A string showing the field's class name, key, and help text.
    """
    return f'{self.__class__.__name__}(key="{self.key}", help="{self.help}")'

is_container()

Check if this field is a container type.

Returns:

Name Type Description
bool

True if this field has a children_class attribute,

indicating it can contain nested configuration values.

Source code in superconf/fields.py
def is_container(self):
    """Check if this field is a container type.

    Returns:
        bool: True if this field has a children_class attribute,
        indicating it can contain nested configuration values.
    """
    children_class = getattr(self, "children_class", None)
    if children_class is not None:
        return True
    return False

resolve_value(conf_instance, value=NOT_SET, default=NOT_SET, cast=NOT_SET, loaders=NOT_SET, lookup=True, **kwargs)

Resolve the final value for this field.

This method handles the complex logic of determining the field's value by: 1. Checking for explicitly provided values 2. Looking up values through loaders 3. Falling back to defaults 4. Applying type casting

Parameters:

Name Type Description Default
conf_instance

The configuration instance this field belongs to.

required
value

Explicitly provided value, takes precedence if set.

NOT_SET
default

Override for the field's default value.

NOT_SET
cast

Override for the field's cast function.

NOT_SET
loaders

List of loader objects to use for value lookup.

NOT_SET
lookup

Enable loaders, or only use _value instead.

True
**kwargs

Additional keyword arguments passed to loaders.

{}

Returns:

Name Type Description
tuple

A tuple containing: - The resolved and cast value - A SimpleNamespace containing metadata about the resolution process

Raises:

Type Description
CastValueFailure

If strict casting is enabled and the value cannot be cast to the desired type.

Source code in superconf/fields.py
def resolve_value(
    self,
    conf_instance,
    value=NOT_SET,
    default=NOT_SET,
    cast=NOT_SET,
    loaders=NOT_SET,
    lookup=True,
    **kwargs,
):
    """Resolve the final value for this field.

    This method handles the complex logic of determining the field's value by:
    1. Checking for explicitly provided values
    2. Looking up values through loaders
    3. Falling back to defaults
    4. Applying type casting

    Args:
        conf_instance: The configuration instance this field belongs to.
        value: Explicitly provided value, takes precedence if set.
        default: Override for the field's default value.
        cast: Override for the field's cast function.
        loaders: List of loader objects to use for value lookup.
        lookup: Enable loaders, or only use _value instead.
        **kwargs: Additional keyword arguments passed to loaders.

    Returns:
        tuple: A tuple containing:
            - The resolved and cast value
            - A SimpleNamespace containing metadata about the resolution process

    Raises:
        CastValueFailure: If strict casting is enabled and the value
            cannot be cast to the desired type.
    """
    key = self.key
    assert isinstance(key, (str, int)), f"Got: {type(key)} {key}"

    # Process defaults
    default_from = ["args"]
    if default is NOT_SET and isinstance(conf_instance._default, dict):
        # Fetch default from container

        # default2 = default
        try:
            default = conf_instance.query_inst_cfg(
                "default", override=kwargs, default=NOT_SET
            )[key]
            default_from.append("conf_instance_query")
        except KeyError:
            pass

    if default is NOT_SET:
        # Fetch default from field
        default = self.default
        default_from.append("field_instance")

    # Process value
    if value is NOT_SET:
        # Fetch default from container
        try:
            value = conf_instance._value[key]
        except (TypeError, KeyError):  # For dict
            pass
        except IndexError:  # For list
            pass

    # Process cast
    cast_from = []
    if cast is NOT_SET:
        cast = self.cast
        cast_from.append(f"field_attr:{self}.cast")
    if cast is NOT_SET:
        cast = conf_instance._cast
        cast_from.append(f"conf_attr:{conf_instance}._cast")

    # Process loaders
    if not lookup:
        loaders = [_Value({key: value})]
    else:
        if loaders is NOT_SET:
            loaders = conf_instance._loaders
        if value:
            # pylint: disable=using-constant-test
            if False:
                loaders.insert(0, _Value({key: value}))
            else:
                # Remove any existing _Value
                loaders = [
                    loader for loader in loaders if not isinstance(loader, _Value)
                ]
                loaders.append(_Value({key: value}))

    # Determine cast method
    if callable(cast):
        # cast = cast
        cast_from.append("cast_is_callable")
    elif cast is None and (default is NOT_SET or default is None):
        cast = as_is
        cast_from.append("cast_is_none_and_no_defaults")
    elif isinstance(default, bool):
        cast = as_boolean
        cast_from.append("cast_as_boolean")
    elif cast is None:
        cast = type(default)
        cast_from.append("cast_is_none")
    elif cast is NOT_SET:
        if default is NOT_SET or default is None:
            cast_from.append("cast_notset_type_default")
            cast = type(default)
        else:
            cast_from.append("cast_notset_type_as_is")
            cast = as_is
    else:
        raise TypeError(f"Cast must be callable, got: {type(cast)}")

    # Process things
    is_casted = False
    result = NOT_SET
    loader_from = []
    results_from = []
    # print(f"ACTUAL LOADERS FOR {self}", loaders)
    logger.debug("Current loaders for %s: %s", self, loaders)
    for loader in loaders:
        loader_from.append(str(loader))
        try:
            logger.debug("Try loader for %s.%s: %s", self, key, loaders)
            # print(f"  > LOADER: try search in {loader} key: {key}")
            # print("VS", self, conf_instance)
            result = loader.getitem(conf_instance, key, **kwargs)

        except KeyError:
            continue

        if result is not NOT_SET:
            results_from.append(f"from_loader:{loader}")
            result = cast(result)
            is_casted = True
            break

    # Nothing found in all loaders, then fallback on default
    if result is NOT_SET:
        result = value
        results_from.append("from_value")
    if result is NOT_SET:
        result = default
        results_from.append("from_default")

    # Try to cast value
    if not is_casted:
        error = None
        try:
            result = cast(result)
            results_from.append(f"casted:{cast}")
        except (exceptions.InvalidCastConfiguration, ValueError, TypeError) as err:
            error = err
            result = NOT_SET
            results_from.append(f"not_castable:{cast}")

        # Check for strict_cast mode:
        if error is not None and conf_instance._strict_cast is True:
            msg = (
                f"Got error {conf_instance}.{key} {type(error)}: {error}, "
                "set strict_cast=False to disable this error"
            )
            raise exceptions.CastValueFailure(msg)

    meta = SimpleNamespace(
        cast=cast,
        default=default,
        loaders=loaders,
        value=result,
        cast_from=cast_from,
        loader_from=loader_from,
        results_from=results_from,
        default_from=default_from,
    )

    return result, meta

FieldBool

Bases: Field

A field that stores and validates boolean values.

Uses the AsBoolean cast to convert various string representations to boolean values (e.g., 'yes'/'no', 'true'/'false', '1'/'0').

Attributes:

Name Type Description
cast

Set to AsBoolean() for automatic type conversion.

Source code in superconf/fields.py
class FieldBool(Field):
    """A field that stores and validates boolean values.

    Uses the AsBoolean cast to convert various string representations
    to boolean values (e.g., 'yes'/'no', 'true'/'false', '1'/'0').

    Attributes:
        cast: Set to AsBoolean() for automatic type conversion.
    """

    cast = as_boolean

FieldConf

Bases: Field

A field that represents a nested configuration.

This field type allows for hierarchical configuration structures by containing another configuration class as its value.

Attributes:

Name Type Description
children_class

The configuration class to use for nested values.

Source code in superconf/fields.py
class FieldConf(Field):
    """A field that represents a nested configuration.

    This field type allows for hierarchical configuration structures by containing
    another configuration class as its value.

    Attributes:
        children_class: The configuration class to use for nested values.
    """

    def __init__(
        self,
        children_class,
        key: str = None,
        **kwargs,
    ):
        """Initialize a nested configuration field.

        Args:
            children_class: The configuration class to use for nested values.
            key: Name of the value used in file or environment variable.
            **kwargs: Additional arguments passed to the parent Field class.
        """
        super().__init__(key, **kwargs)
        self.children_class = children_class

__init__(children_class, key=None, **kwargs)

Initialize a nested configuration field.

Parameters:

Name Type Description Default
children_class

The configuration class to use for nested values.

required
key str

Name of the value used in file or environment variable.

None
**kwargs

Additional arguments passed to the parent Field class.

{}
Source code in superconf/fields.py
def __init__(
    self,
    children_class,
    key: str = None,
    **kwargs,
):
    """Initialize a nested configuration field.

    Args:
        children_class: The configuration class to use for nested values.
        key: Name of the value used in file or environment variable.
        **kwargs: Additional arguments passed to the parent Field class.
    """
    super().__init__(key, **kwargs)
    self.children_class = children_class

FieldDict

Bases: Field

A field that stores dictionary values.

Uses the AsDict cast to ensure values are proper dictionaries, with support for converting mapping objects.

Attributes:

Name Type Description
cast

Set to AsDict() for automatic type conversion.

Source code in superconf/fields.py
class FieldDict(Field):
    """A field that stores dictionary values.

    Uses the AsDict cast to ensure values are proper dictionaries,
    with support for converting mapping objects.

    Attributes:
        cast: Set to AsDict() for automatic type conversion.
    """

    cast = as_dict

FieldFloat

Bases: Field

A field that stores floating-point values.

Uses Python's built-in float() function to convert values, raising an error if the conversion fails.

Attributes:

Name Type Description
cast

Set to float for automatic type conversion.

Source code in superconf/fields.py
class FieldFloat(Field):
    """A field that stores floating-point values.

    Uses Python's built-in float() function to convert values,
    raising an error if the conversion fails.

    Attributes:
        cast: Set to float for automatic type conversion.
    """

    cast = float

FieldInt

Bases: Field

A field that stores integer values.

Uses the AsInt cast to convert string representations to integers, raising an error if the conversion fails.

Attributes:

Name Type Description
cast

Set to AsInt() for automatic type conversion.

Source code in superconf/fields.py
class FieldInt(Field):
    """A field that stores integer values.

    Uses the AsInt cast to convert string representations to integers,
    raising an error if the conversion fails.

    Attributes:
        cast: Set to AsInt() for automatic type conversion.
    """

    cast = as_int

FieldList

Bases: Field

A field that stores list values.

Uses the AsList cast to convert various inputs to lists, including: - Comma-separated strings - Other sequence types - Empty values to empty lists

Attributes:

Name Type Description
cast

Set to AsList() for automatic type conversion.

Source code in superconf/fields.py
class FieldList(Field):
    """A field that stores list values.

    Uses the AsList cast to convert various inputs to lists, including:
    - Comma-separated strings
    - Other sequence types
    - Empty values to empty lists

    Attributes:
        cast: Set to AsList() for automatic type conversion.
    """

    cast = as_list

FieldOption

Bases: Field

A field that validates values against a predefined set of options.

This field ensures that values are one of a predefined set of options, optionally providing a default if an invalid option is given.

Attributes:

Name Type Description
cast

Set to AsOption for option validation and conversion.

Source code in superconf/fields.py
class FieldOption(Field):
    """A field that validates values against a predefined set of options.

    This field ensures that values are one of a predefined set of options,
    optionally providing a default if an invalid option is given.

    Attributes:
        cast: Set to AsOption for option validation and conversion.
    """

    cast = as_option

    def __init__(
        self,
        options,
        default_option=FAIL,
        key: str = None,
        **kwargs,
    ):
        """Initialize an option field.

        Args:
            options: Dictionary mapping valid input values to their corresponding options.
            default_option: The option to use when an invalid value is provided.
                If set to FAIL, raises an error for invalid values.
            key: Name of the value used in file or environment variable.
            **kwargs: Additional arguments passed to the parent Field class.

        Raises:
            AssertionError: If options is not a dictionary.
        """
        assert isinstance(options, dict), f"Expected a dict, got: {options}"
        self.cast = AsOption(options, default_option=default_option)
        super().__init__(key, **kwargs)

__init__(options, default_option=FAIL, key=None, **kwargs)

Initialize an option field.

Parameters:

Name Type Description Default
options

Dictionary mapping valid input values to their corresponding options.

required
default_option

The option to use when an invalid value is provided. If set to FAIL, raises an error for invalid values.

FAIL
key str

Name of the value used in file or environment variable.

None
**kwargs

Additional arguments passed to the parent Field class.

{}

Raises:

Type Description
AssertionError

If options is not a dictionary.

Source code in superconf/fields.py
def __init__(
    self,
    options,
    default_option=FAIL,
    key: str = None,
    **kwargs,
):
    """Initialize an option field.

    Args:
        options: Dictionary mapping valid input values to their corresponding options.
        default_option: The option to use when an invalid value is provided.
            If set to FAIL, raises an error for invalid values.
        key: Name of the value used in file or environment variable.
        **kwargs: Additional arguments passed to the parent Field class.

    Raises:
        AssertionError: If options is not a dictionary.
    """
    assert isinstance(options, dict), f"Expected a dict, got: {options}"
    self.cast = AsOption(options, default_option=default_option)
    super().__init__(key, **kwargs)

FieldString

Bases: Field

A field that stores string values.

Ensures values are stored as strings, converting other types if necessary using Python's built-in str() function.

Attributes:

Name Type Description
cast

Set to str for automatic type conversion.

Source code in superconf/fields.py
class FieldString(Field):
    """A field that stores string values.

    Ensures values are stored as strings, converting other types
    if necessary using Python's built-in str() function.

    Attributes:
        cast: Set to str for automatic type conversion.
    """

    cast = str

FieldTuple

Bases: Field

A field that stores tuple values.

Uses the AsTuple cast to convert various inputs to tuples, including: - Comma-separated strings - Other sequence types - Empty values to empty tuples

Attributes:

Name Type Description
cast

Set to AsTuple() for automatic type conversion.

Source code in superconf/fields.py
class FieldTuple(Field):
    """A field that stores tuple values.

    Uses the AsTuple cast to convert various inputs to tuples, including:
    - Comma-separated strings
    - Other sequence types
    - Empty values to empty tuples

    Attributes:
        cast: Set to AsTuple() for automatic type conversion.
    """

    cast = as_tuple