Skip to content

Config Module🔗

The earthdaily.earthone.config module provides configuration management using Dynaconf, including environment selection and settings access.

Settings🔗

Settings 🔗

Bases: Dynaconf

Configuration settings for the EarthOne client.

Based on the Dynaconf package. This settings class supports configuration from named "environments" in a settings.toml file as well as environment variables with names that are prefixed with EARTHONE_ (or the prefix specified in the envvar_prefix).

For the full capabilities of Dynaconf please consult https://www.dynaconf.com/.

Note that normally Settings functions entirely automatically within the client. However, it is possible to perform custom initialization programmatically. In order to do this, the beginning of the client program must execute code like this:

.. code-block::

from earthdaily.earthone.config import Settings
Settings.select_env(...)

Before importing or otherwise accessing anything else within the 🇵🇾mod:earthdaily-earthone package.

Source code in earthdaily/earthone/config/__init__.py
class Settings(dynaconf.Dynaconf):
    """
    Configuration settings for the EarthOne client.

    Based on the ``Dynaconf`` package. This settings class supports configuration from
    named "environments" in a ``settings.toml`` file as well as environment variables
    with names that are prefixed with ``EARTHONE_`` (or the prefix specified
    in the ``envvar_prefix``).

    For the full capabilities of ``Dynaconf`` please consult https://www.dynaconf.com/.

    Note that normally ``Settings`` functions entirely automatically within the client.
    However, it is possible to perform custom initialization programmatically. In order
    to do this, the beginning of the client program must execute code like this:

    .. code-block::

        from earthdaily.earthone.config import Settings
        Settings.select_env(...)

    Before importing or otherwise accessing anything else within the
    :py:mod:`earthdaily-earthone` package.
    """

    class _EnvDescriptor:
        # Retrieve the correct env string for `peek_settings()`
        def __get__(self, obj, objtype=None):
            if obj is None:
                if objtype._settings is None:
                    return None
                else:
                    return objtype._settings.env_for_dynaconf
            else:
                return obj.env_for_dynaconf

    env = _EnvDescriptor()
    """str : The current client configuration name or `None` of no environment was selected."""

    # The global settings instance, can only be set once via select_env or get_settings
    _settings = None

    _lock = Lock()

    @classmethod
    def select_env(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
        """
        Configure the EarthOne client.

        Parameters
        ----------
        env : str, optional
            Name of the environment to configure. Must appear in
            ``earthdaily.earthone/config/settings.toml`` If not supplied will be determined
            from the `EARTHONE_ENV` environment variable (or use the prefix
            specified in the `envvar_prefix`_ENV), if set. Otherwise defaults to
            `production`.
        settings_file : str, optional
            If supplied, will be consulted for additional configuration overrides. These
            are applied over those in the ``earthdaily.earthone/config/settings.toml`` file,
            but are themselves overwritten by any environment variable settings matching
            the `envvar_prefix`.
        envvar_prefix : str, optional
            Prefix for environment variable names to consult for configuration
            overrides. Environment variables with a leading prefix of
            ``"<envvar_prefix>_"`` will override the settings in the resulting
            configuration after the settings file(s) have been consulted.

        Returns
        -------
        Settings
            Returns a ``Settings`` instance, a dict-like object
            containing the configured settings for the client.

        Raises
        ------
        ConfigError
            If no client configuration could be established, or if an invalid
            configuration name was specified, or if you try to change the
            client configuration after the client is already configured.
        """
        # Once the settings has been lazy evaluated, we cannot change it.
        # The reviled double-check pattern. Actually ok with CPython and the GIL,
        # but not necessarily any other Python implementation.
        settings = cls._settings

        if settings is None:
            with cls._lock:
                settings = cls._settings

                if settings is None:
                    settings = cls._select_env(
                        env=env,
                        settings_file=settings_file,
                        envvar_prefix=envvar_prefix,
                    )

        if settings is not None and env is not None and env != settings.ENV:
            raise ConfigError(
                f"Client configuration '{settings.ENV}' has already been selected"
            )

        return settings

    @classmethod
    def get_settings(cls):
        """
        Configure and retrieve the current or default settings for the client.

        Returns
        -------
        Settings
            Returns a ``Settings`` instance, a dict-like object
            containing the configured settings for the client.

        Raises
        ------
        ConfigError
            If no client configuration could be established, or if an invalid
            configuration name was specified, or if you try to change the
            client configuration after the client is already configured.
        """
        # The reviled double-check pattern. Actually ok with CPython and the GIL,
        # but not necessarily any other Python implementation.
        settings = cls._settings

        if settings is None:
            with cls._lock:
                settings = cls._settings
                if settings is None:
                    settings = cls._select_env()

        return settings

    @classmethod
    def peek_settings(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
        """Retrieve the settings without configuring the client.

        Unlike :py:meth:`~Settings.get_settings` and :py:meth:`~Settings.select_env`
        which both will configure the client, the :py:meth:`~Settings.peek_settings`
        will not configure the client and :py:attr:`Settings.env` will not be set.

        See :py:meth:`select_env` for an explanation of the parameters, return value,
        and exceptions that can be raised.
        """
        selector = f"{envvar_prefix}_ENV"
        original_selector_value = os.environ.get(selector)

        settings = cls._get_settings(
            env=env,
            settings_file=settings_file,
            envvar_prefix=envvar_prefix,
        )

        # Return the environ back to its original state
        if original_selector_value is None:
            os.environ.pop(selector)
        else:
            os.environ[selector] = original_selector_value

        return settings

    @classmethod
    def _select_env(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
        # Assign to the global instance.
        cls._settings = cls._get_settings(
            env=env, settings_file=settings_file, envvar_prefix=envvar_prefix
        )

        # And return the settings object.
        return cls._settings

    @classmethod
    def _get_settings(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
        # Get the settings. If the settings are retrieved successfully, the os.environ
        # will contain the selector for the given settings.
        selector = f"{envvar_prefix}_ENV"
        original_selector_value = os.environ.get(selector)

        def restore_env():
            if original_selector_value is None:
                os.environ.pop(selector)
            else:
                os.environ[selector] = original_selector_value

        if env:
            os.environ[selector] = env
        elif not os.environ.get(selector):
            # Default it.
            os.environ[selector] = DEFAULT_ENVIRONMENT

        builtin_settings_file = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "settings.toml"
        )

        try:
            # By default this will load from one or more settings files and
            # then from the environment.
            settings = cls(
                # First load our client settings from TOML file.
                settings_file=[builtin_settings_file],
                # Then load the given settings from TOML file, if any.
                includes=[] if not settings_file else [settings_file],
                # Only allow TOML format.
                core_loaders=["TOML"],
                # Allow multiple environments ([default] is always used).
                environments=True,
                # Name of environment variable that selects the environment.
                env_switcher=selector,
                # Prefix to overwrite loaded settings, e.g,. {envvar_prefix}_MY_SETTING.
                envvar_prefix=envvar_prefix,
            )
        except Exception as e:
            restore_env()
            raise ConfigError(str(e)) from e

        try:
            # Make sure we selected an environment!
            assert settings.env_for_dynaconf
            # default_domain must have been set
            assert settings.default_domain
        except (AttributeError, KeyError, AssertionError):
            message = f"Client configuration '{os.environ[selector]}' doesn't exist!"
            restore_env()

            if not env:
                message += " Check your EARTHONE_ENV environment variable."

            raise ConfigError(message) from None

        return settings

env class-attribute instance-attribute 🔗

env = _EnvDescriptor()

str : The current client configuration name or None of no environment was selected.

select_env classmethod 🔗

select_env(env=None, settings_file=None, envvar_prefix='EARTHONE')

Configure the EarthOne client.

Parameters🔗

env : str, optional Name of the environment to configure. Must appear in earthdaily.earthone/config/settings.toml If not supplied will be determined from the EARTHONE_ENV environment variable (or use the prefix specified in the envvar_prefix_ENV), if set. Otherwise defaults to production. settings_file : str, optional If supplied, will be consulted for additional configuration overrides. These are applied over those in the earthdaily.earthone/config/settings.toml file, but are themselves overwritten by any environment variable settings matching the envvar_prefix. envvar_prefix : str, optional Prefix for environment variable names to consult for configuration overrides. Environment variables with a leading prefix of "<envvar_prefix>_" will override the settings in the resulting configuration after the settings file(s) have been consulted.

Returns🔗

Settings Returns a Settings instance, a dict-like object containing the configured settings for the client.

Raises🔗

ConfigError If no client configuration could be established, or if an invalid configuration name was specified, or if you try to change the client configuration after the client is already configured.

Source code in earthdaily/earthone/config/__init__.py
@classmethod
def select_env(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
    """
    Configure the EarthOne client.

    Parameters
    ----------
    env : str, optional
        Name of the environment to configure. Must appear in
        ``earthdaily.earthone/config/settings.toml`` If not supplied will be determined
        from the `EARTHONE_ENV` environment variable (or use the prefix
        specified in the `envvar_prefix`_ENV), if set. Otherwise defaults to
        `production`.
    settings_file : str, optional
        If supplied, will be consulted for additional configuration overrides. These
        are applied over those in the ``earthdaily.earthone/config/settings.toml`` file,
        but are themselves overwritten by any environment variable settings matching
        the `envvar_prefix`.
    envvar_prefix : str, optional
        Prefix for environment variable names to consult for configuration
        overrides. Environment variables with a leading prefix of
        ``"<envvar_prefix>_"`` will override the settings in the resulting
        configuration after the settings file(s) have been consulted.

    Returns
    -------
    Settings
        Returns a ``Settings`` instance, a dict-like object
        containing the configured settings for the client.

    Raises
    ------
    ConfigError
        If no client configuration could be established, or if an invalid
        configuration name was specified, or if you try to change the
        client configuration after the client is already configured.
    """
    # Once the settings has been lazy evaluated, we cannot change it.
    # The reviled double-check pattern. Actually ok with CPython and the GIL,
    # but not necessarily any other Python implementation.
    settings = cls._settings

    if settings is None:
        with cls._lock:
            settings = cls._settings

            if settings is None:
                settings = cls._select_env(
                    env=env,
                    settings_file=settings_file,
                    envvar_prefix=envvar_prefix,
                )

    if settings is not None and env is not None and env != settings.ENV:
        raise ConfigError(
            f"Client configuration '{settings.ENV}' has already been selected"
        )

    return settings

get_settings classmethod 🔗

get_settings()

Configure and retrieve the current or default settings for the client.

Returns🔗

Settings Returns a Settings instance, a dict-like object containing the configured settings for the client.

Raises🔗

ConfigError If no client configuration could be established, or if an invalid configuration name was specified, or if you try to change the client configuration after the client is already configured.

Source code in earthdaily/earthone/config/__init__.py
@classmethod
def get_settings(cls):
    """
    Configure and retrieve the current or default settings for the client.

    Returns
    -------
    Settings
        Returns a ``Settings`` instance, a dict-like object
        containing the configured settings for the client.

    Raises
    ------
    ConfigError
        If no client configuration could be established, or if an invalid
        configuration name was specified, or if you try to change the
        client configuration after the client is already configured.
    """
    # The reviled double-check pattern. Actually ok with CPython and the GIL,
    # but not necessarily any other Python implementation.
    settings = cls._settings

    if settings is None:
        with cls._lock:
            settings = cls._settings
            if settings is None:
                settings = cls._select_env()

    return settings

peek_settings classmethod 🔗

peek_settings(env=None, settings_file=None, envvar_prefix='EARTHONE')

Retrieve the settings without configuring the client.

Unlike 🇵🇾meth:~Settings.get_settings and 🇵🇾meth:~Settings.select_env which both will configure the client, the 🇵🇾meth:~Settings.peek_settings will not configure the client and 🇵🇾attr:Settings.env will not be set.

See 🇵🇾meth:select_env for an explanation of the parameters, return value, and exceptions that can be raised.

Source code in earthdaily/earthone/config/__init__.py
@classmethod
def peek_settings(cls, env=None, settings_file=None, envvar_prefix="EARTHONE"):
    """Retrieve the settings without configuring the client.

    Unlike :py:meth:`~Settings.get_settings` and :py:meth:`~Settings.select_env`
    which both will configure the client, the :py:meth:`~Settings.peek_settings`
    will not configure the client and :py:attr:`Settings.env` will not be set.

    See :py:meth:`select_env` for an explanation of the parameters, return value,
    and exceptions that can be raised.
    """
    selector = f"{envvar_prefix}_ENV"
    original_selector_value = os.environ.get(selector)

    settings = cls._get_settings(
        env=env,
        settings_file=settings_file,
        envvar_prefix=envvar_prefix,
    )

    # Return the environ back to its original state
    if original_selector_value is None:
        os.environ.pop(selector)
    else:
        os.environ[selector] = original_selector_value

    return settings

get_settings🔗

get_settings module-attribute 🔗

get_settings = get_settings

An alias for 🇵🇾meth:Settings.get_settings


select_env🔗

select_env module-attribute 🔗

select_env = select_env