Skip to content

Config Util

oqtopus_util.config provides utility functions for loading YAML configuration files with environment-variable substitution, masking sensitive values, and applying logging configuration.

Functions

load_config

from oqtopus_util.config import load_config

config = load_config("config/config.yaml")

load_config(config_path) reads a YAML file and returns a Python dict.

Before the file is parsed by PyYAML, every ${VAR} and ${VAR, default} placeholder is replaced at the string level, allowing YAML to apply its own type-casting rules.

Placeholder Environment variable set Result
${VAR} Yes Raw value of VAR (string; YAML casts the surrounding context)
${VAR} No null (YAML None)
${VAR, default} Yes Raw value of VAR
${VAR, default} No default — YAML type-casts it (e.g. 10int, falsebool)
${VAR, "default"} Yes Raw value of VAR
${VAR, "default"} No "default" — YAML treats it as a string (quotes suppress type-casting)
${VAR, 'default'} Yes Raw value of VAR
${VAR, 'default'} No 'default' — same as double-quoted form

Quoting the default value allows } to appear inside it. Without quotes, } would be interpreted as the closing delimiter of the ${...} expression.

String values that start with ~ are expanded to absolute home-directory paths (equivalent to Path(value).expanduser()).

Example config.yaml

server:
  host: ${HOST, localhost}
  port: ${PORT, 8080}
  debug: ${DEBUG, false}
  data_dir: ~/oqtopus/data
  template: ${TEMPLATE, "/base/{key}/sub"}
import os
from oqtopus_util.config import load_config

os.environ["HOST"] = "example.com"

cfg = load_config("config/config.yaml")
# cfg["server"]["host"]       == "example.com"
# cfg["server"]["port"]       == 8080          (int, cast by YAML)
# cfg["server"]["debug"]      is False         (bool, cast by YAML)
# cfg["server"]["data_dir"]   == "/home/user/oqtopus/data"
# cfg["server"]["template"]   == "/base/{key}/sub"        (str, quotes suppress casting)

mask_sensitive_info

from oqtopus_util.config import mask_sensitive_info

safe_cfg = mask_sensitive_info(config)

mask_sensitive_info(config) returns a copy of the configuration dictionary where sensitive values are replaced with "***MASKED***".

A key is treated as sensitive when its name (case-insensitive) contains any of the following substrings:

Substring Example keys that match
key api_key, openai_api_key
password password, db_password
secret secret, client_secret
token token, access_token

The function processes nested dictionaries recursively, so sensitive values at any depth are masked.

Note

This function is designed for small configuration dicts loaded at startup and is not intended for large data sets.

Example: mask_sensitive_info

from oqtopus_util.config import mask_sensitive_info

config = {
    "database": {
        "host": "localhost",
        "db_password": "s3cr3t",
    },
    "openai_api_key": "abc123",
    "access_token": "tok456",
}

safe = mask_sensitive_info(config)
# safe["database"]["db_password"] == "***MASKED***"
# safe["openai_api_key"]          == "***MASKED***"
# safe["access_token"]            == "***MASKED***"
# safe["database"]["host"]        == "localhost"

setup_logging

from oqtopus_util.config import setup_logging

setup_logging(logging_cfg)

setup_logging(logging_cfg) applies a logging configuration dictionary by calling logging.config.dictConfig.

The logging_cfg argument must be a Python dict. A TypeError is raised if a non-dict value is passed.

Example: setup_logging

from oqtopus_util.config import load_config, setup_logging

logging_cfg = load_config("config/logging.yaml")
setup_logging(logging_cfg)

Example logging.yaml

version: 1
formatters:
  default:
    format: "%(asctime)s %(levelname)s %(message)s"
handlers:
  console:
    class: logging.StreamHandler
    formatter: default
    stream: ext://sys.stdout
root:
  level: INFO
  handlers: [console]
disable_existing_loggers: false

Complete Example

import logging
from oqtopus_util.config import load_config, mask_sensitive_info, setup_logging

# Load main configuration
config = load_config("config/config.yaml")

# Set up logging first
logging_cfg = load_config("config/logging.yaml")
setup_logging(logging_cfg)

logger = logging.getLogger(__name__)

# Log configuration without exposing secrets
safe_cfg = mask_sensitive_info(config)
logger.info("Loaded configuration: %s", safe_cfg)