Skip to content

核心与配置

BaseModule

Bases: ABC

Abstract base class for all modules in aloha.

Provides common attributes to all modules: - config: Global configuration object - LOG: Logger instance

Source code in aloha/base.py
class BaseModule(ABC):
    """
    Abstract base class for all modules in aloha.

    Provides common attributes to all modules:
    - config: Global configuration object
    - LOG: Logger instance
    """

    config = SETTINGS.config
    LOG = LOG

Settings

Global settings management class for the Aloha package.

This class manages the lazy loading of HOCON configuration files, environment profile resolution, and provides access to project resource and configuration directories.

Attributes: _config (Any | None): Internal storage for the parsed configuration.

Source code in aloha/settings.py
class Settings:
    """
    Global settings management class for the Aloha package.

    This class manages the lazy loading of HOCON configuration files, environment
    profile resolution, and provides access to project resource and configuration directories.

    Attributes:
        _config (Any | None): Internal storage for the parsed configuration.
    """

    def __init__(self, config: Any | None = None):
        """
        Initialize the Settings manager.

        :param config: Optional pre-loaded configuration dictionary, list, or None.
                       If provided, it is parsed and loaded immediately.
        """
        if config is None:
            self._config = None
        else:
            self.load_settings(config)

    @property
    def dir_resource(self):
        """
        Get the absolute path of the resource directory.

        Resolves dynamically based on the `DIR_RESOURCE` environment variable,
        falling back to the default 'resource' directory in the current working directory.

        :return: Absolute path to the resource directory.
        """
        return paths.get_resource_dir()

    @property
    def dir_config(self):
        """
        Get the absolute path of the configuration directory.

        Resolves dynamically based on the `DIR_CONFIG` environment variable,
        falling back to the 'config' subdirectory under the resource directory.

        :return: Absolute path to the configuration directory.
        """
        return paths.get_config_dir()

    def load_settings(self, config: Any) -> Any:
        """
        Recursively load and transform configuration values.

        Converts raw dictionaries into `AttrDict` objects to support attribute-style
        dot notation access, and recursively processes lists and nested values.

        :param config: The configuration data to load (dict or list).
        :return: The converted configuration object (AttrDict or list).
        :raises ValueError: If the configuration data type is unsupported.
        """
        if isinstance(config, dict):
            self._config = AttrDict({key: self.load_settings(value) for key, value in config.items()})
        elif isinstance(config, list):
            self._config = [self.load_settings(value) for value in config]
        else:
            raise ValueError("Unsupported config type: %s" % str(type(config)))
        return self._config

    @property
    def config(self):
        """
        Get the global configuration object.

        Lazily loads and parses configuration files on first access. It resolves active
        HOCON configuration files based on the `FILES_CONFIG` or `ENV_PROFILE` environment
        variables, falls back to `main.conf` if not specified, and merges them into an `AttrDict`.

        :return: Merged global configuration settings as an AttrDict.
        """
        if self._config is None:
            config_files = paths.get_config_files()  # by default, use the `main.conf` file in the config_dir
            self._config = hocon.load_config_from_hocon_files(config_files, base_dir=paths.get_config_dir())

        return self._config

    def __getitem__(self, item):
        """
        Get a configuration value using dictionary key lookup syntax.

        Allows retrieving configurations using `SETTINGS[key]`.

        :param item: The configuration key to look up.
        :return: The resolved configuration value.
        """
        return self.config[item]

config property

Get the global configuration object.

Lazily loads and parses configuration files on first access. It resolves active HOCON configuration files based on the FILES_CONFIG or ENV_PROFILE environment variables, falls back to main.conf if not specified, and merges them into an AttrDict.

Returns:

Type Description

Merged global configuration settings as an AttrDict.

dir_config property

Get the absolute path of the configuration directory.

Resolves dynamically based on the DIR_CONFIG environment variable, falling back to the 'config' subdirectory under the resource directory.

Returns:

Type Description

Absolute path to the configuration directory.

dir_resource property

Get the absolute path of the resource directory.

Resolves dynamically based on the DIR_RESOURCE environment variable, falling back to the default 'resource' directory in the current working directory.

Returns:

Type Description

Absolute path to the resource directory.

__getitem__(item)

Get a configuration value using dictionary key lookup syntax.

Allows retrieving configurations using SETTINGS[key].

Parameters:

Name Type Description Default
item

The configuration key to look up.

required

Returns:

Type Description

The resolved configuration value.

Source code in aloha/settings.py
def __getitem__(self, item):
    """
    Get a configuration value using dictionary key lookup syntax.

    Allows retrieving configurations using `SETTINGS[key]`.

    :param item: The configuration key to look up.
    :return: The resolved configuration value.
    """
    return self.config[item]

__init__(config=None)

Initialize the Settings manager.

Parameters:

Name Type Description Default
config Any | None

Optional pre-loaded configuration dictionary, list, or None. If provided, it is parsed and loaded immediately.

None
Source code in aloha/settings.py
def __init__(self, config: Any | None = None):
    """
    Initialize the Settings manager.

    :param config: Optional pre-loaded configuration dictionary, list, or None.
                   If provided, it is parsed and loaded immediately.
    """
    if config is None:
        self._config = None
    else:
        self.load_settings(config)

load_settings(config)

Recursively load and transform configuration values.

Converts raw dictionaries into AttrDict objects to support attribute-style dot notation access, and recursively processes lists and nested values.

Parameters:

Name Type Description Default
config Any

The configuration data to load (dict or list).

required

Returns:

Type Description
Any

The converted configuration object (AttrDict or list).

Raises:

Type Description
ValueError

If the configuration data type is unsupported.

Source code in aloha/settings.py
def load_settings(self, config: Any) -> Any:
    """
    Recursively load and transform configuration values.

    Converts raw dictionaries into `AttrDict` objects to support attribute-style
    dot notation access, and recursively processes lists and nested values.

    :param config: The configuration data to load (dict or list).
    :return: The converted configuration object (AttrDict or list).
    :raises ValueError: If the configuration data type is unsupported.
    """
    if isinstance(config, dict):
        self._config = AttrDict({key: self.load_settings(value) for key, value in config.items()})
    elif isinstance(config, list):
        self._config = [self.load_settings(value) for value in config]
    else:
        raise ValueError("Unsupported config type: %s" % str(type(config)))
    return self._config

get_config_dir(*args)

Get the configuration directory path. The config directory is determined by: 1. If DIR_CONFIG environment variable is set, use it; 2. Otherwise, default to 'config' directory under resource directory.

Parameters:

Name Type Description Default
args

Additional path components to append to the config directory

()

Returns:

Type Description
str

Config directory path

Source code in aloha/config/paths.py
def get_config_dir(*args) -> str:
    """
    Get the configuration directory path.
    The config directory is determined by:
    1. If DIR_CONFIG environment variable is set, use it;
    2. Otherwise, default to 'config' directory under resource directory.

    :param args: Additional path components to append to the config directory
    :return: Config directory path
    """
    dir_config = os.environ.get("DIR_CONFIG")
    dir_resource = get_resource_dir()
    if dir_config is None or len(dir_config.strip()) == 0:
        dir_config = "config"
    dir_config = path_join(dir_resource, dir_config, *args)
    return dir_config

get_config_files()

Get a list of config files to parse. The base dir of config files should be specified by get_config_dir(). 1. The function will look up the FILES_CONFIG environment variable to get a list of file names seperated by comma, if specified; 2. In case FILES_CONFIG is not specified, the function will use the default config file; 3. The default config file is determined by: (a) If environment variable ENV_PROFILE is defined, the entry file will be "main-{ENV_PROFILE}.conf" (b) If environment variable ENV_PROFILE is not defined, the entry config file will be "main.conf".

Returns:

Type Description
list

list of string, which are file names of config files

Source code in aloha/config/paths.py
def get_config_files() -> list:
    """
    Get a list of config files to parse. The base dir of config files should be specified by `get_config_dir()`.
    1. The function will look up the `FILES_CONFIG` environment variable to get a list of file names seperated by comma, if specified;
    2. In case `FILES_CONFIG` is not specified, the function will use the default config file;
    3. The default config file is determined by:
       (a) If environment variable `ENV_PROFILE` is defined, the entry file will be "main-{ENV_PROFILE}.conf"
       (b) If environment variable `ENV_PROFILE` is not defined, the entry config file will be "main.conf".
    :return: list of string, which are file names of config files
    """
    files_config = os.environ.get("FILES_CONFIG", None)
    if files_config is None:
        env_profile = os.environ.get("ENV_PROFILE", None)
        if env_profile is None:
            files_config = "main.conf"
        else:
            files_config = "main-%s.conf" % env_profile

    files = files_config.split(",")
    ret = []
    msgs = []
    for f in files:
        file = get_config_dir(f)
        if not os.path.exists(file):
            msgs.append("Expecting config file [%s] but it does not exists!" % file)
        else:
            print("  ---> Loading config file [%s]" % file, file=sys.stderr)
            ret.append(os.path.expandvars(f))
    if len(ret) == 0:
        msgs.append("No config files set properly, EMPTY config will be used!")

    if len(msgs) > 0:
        warnings.warn("\n".join(msgs))
    return ret

get_current_module_dir(file_caller)

Get the directory containing the given module file.

Parameters:

Name Type Description Default
file_caller str

Path to the module file (usually file)

required

Returns:

Type Description
str

Directory path of the module

Source code in aloha/config/paths.py
def get_current_module_dir(file_caller: str) -> str:
    """
    Get the directory containing the given module file.

    :param file_caller: Path to the module file (usually __file__)
    :return: Directory path of the module
    """
    dirs = file_caller.split(os.sep)
    return os.sep.join(dirs[:-1])

get_project_base_dir(file_caller)

Get the project base directory by searching upwards for init.py. Starts from the given file path and moves up until a directory without init.py is found, indicating the project root.

Parameters:

Name Type Description Default
file_caller str

Path to the starting file (usually file)

required

Returns:

Type Description
str

Project base directory path

Source code in aloha/config/paths.py
def get_project_base_dir(file_caller: str) -> str:
    """
    Get the project base directory by searching upwards for __init__.py.
    Starts from the given file path and moves up until a directory without
    __init__.py is found, indicating the project root.

    :param file_caller: Path to the starting file (usually __file__)
    :return: Project base directory path
    """
    dirs = file_caller.split(os.sep)

    dir_base = ""
    for i in range(len(dirs)):
        dir_base = os.sep.join(dirs[: -1 - i])
        file_init = path_join(dir_base, "__init__.py")
        if not os.path.exists(file_init):
            break
    return dir_base

get_resource_dir(*args)

Get the resource directory path. The resource directory is determined by: 1. If DIR_RESOURCE environment variable is set, use it; 2. Otherwise, default to 'resource' directory under current working directory.

Parameters:

Name Type Description Default
args

Additional path components to append to the resource directory

()

Returns:

Type Description
str

Resource directory path

Source code in aloha/config/paths.py
def get_resource_dir(*args) -> str:
    """
    Get the resource directory path.
    The resource directory is determined by:
    1. If DIR_RESOURCE environment variable is set, use it;
    2. Otherwise, default to 'resource' directory under current working directory.

    :param args: Additional path components to append to the resource directory
    :return: Resource directory path
    """
    dir_cwd = os.getcwd()
    dir_resource = os.environ.get("DIR_RESOURCE", "resource")
    return path_join(dir_cwd, dir_resource, *args)

path_join(*args)

Join path components and normalize the result. Performs path joining, user expansion, environment variable expansion, and conversion to absolute path.

Parameters:

Name Type Description Default
args

Path components to join

()

Returns:

Type Description
str

Normalized absolute path string

Source code in aloha/config/paths.py
def path_join(*args) -> str:
    """
    Join path components and normalize the result.
    Performs path joining, user expansion, environment variable expansion,
    and conversion to absolute path.

    :param args: Path components to join
    :return: Normalized absolute path string
    """
    p = os.path.join(*args)
    p = os.path.expanduser(p)
    p = os.path.expandvars(p)
    p = os.path.abspath(p)
    return p

load_config_from_hocon(config_file)

Load configuration from a single HOCON file.

Parameters:

Name Type Description Default
config_file

Path to the HOCON configuration file

required

Returns:

Type Description

Configuration as an ordered dictionary

Source code in aloha/config/hocon.py
def load_config_from_hocon(config_file):
    """
    Load configuration from a single HOCON file.

    :param config_file: Path to the HOCON configuration file
    :return: Configuration as an ordered dictionary
    """
    config = ConfigFactory.parse_file(config_file).as_plain_ordered_dict()
    return config

load_config_from_hocon_files(config_files, base_dir)

Load configuration from multiple HOCON files.

Combines multiple HOCON files using include directives and returns the result as an AttrDict for attribute-style access.

Parameters:

Name Type Description Default
config_files list

List of HOCON configuration file names

required
base_dir str

Base directory for resolving relative paths

required

Returns:

Type Description

Configuration as an AttrDict object

Source code in aloha/config/hocon.py
def load_config_from_hocon_files(config_files: list, base_dir: str):
    """
    Load configuration from multiple HOCON files.

    Combines multiple HOCON files using include directives and returns
    the result as an AttrDict for attribute-style access.

    :param config_files: List of HOCON configuration file names
    :param base_dir: Base directory for resolving relative paths
    :return: Configuration as an AttrDict object
    """
    s = []
    for config_file in config_files:
        f = 'include required("%s")' % config_file
        s.append(f)
    f = "\n".join(s)

    config = ConfigFactory.parse_string(content=f, basedir=base_dir).as_plain_ordered_dict()
    return AttrDict(config)