Skip to main content

Platform-aware configuration management (CLI flags + env + YAML/JSON deep-merge)

Project description

Confumo

Confumo derives from "Confuse more". It's a thin Python module that merges command-line flags, environment variables, and YAML/JSON files into a single, deep-merged configuration object. The object is always a singleton per application name and can be exposed at module scope so existing code keeps working.

One line to register your flags, one line to expose the config to the rest of your project.

Highlights

Description
Merged sources argparse • ENV vars • YAML/JSON • defaults
Singleton registry Only one ArgumentParser run per app_name; mismatched config classes raise instead of silently reusing the wrong singleton
Auto flag inheritance Base class + mix-ins + leaf class all show up in --help
Lazy “print-once” help Libraries defer --help; root application prints merged help
Module-level proxy from my_app.config import log_level still works; alias collisions raise unless explicitly replaced
Deep-merge Powered by confuse
Cross-platform paths Uses platformdirs

Installation

pip install confumo

1 · Define a config class

# ui_layer/config.py
import argparse
from confumo import Confumo

class UIConfig(Confumo):
    def add_args(self, p: argparse.ArgumentParser):
        p.add_argument('--theme', choices=['light', 'dark', 'auto'], default='auto')
        p.add_argument('--font', default='Roboto')

    def _init_subclass(self):
        self.theme = self.args.theme
        self.font = self.cfg['font'].get(str)

    def to_dict(self):
        return {'theme': self.theme, 'font': self.font}

2 · Expose it (library mode)

UIConfig is meant to be reused by many apps, so the library defers --help printing:

# ui_layer/config.py  (bottom of file)
config = Confumo.expose(
    'ui_layer',
    UIConfig,
    globals(),
    root=False,
)

Now any package can do:

from ui_layer import config
print(config.theme)

and the singleton is shared process-wide.

3 · Extend it in an application

# cool_app/config.py
import argparse
from confumo import Confumo
from ui_layer.config import UIConfig

class CoolAppConfig(UIConfig):
    def add_args(self, p: argparse.ArgumentParser):
        p.add_argument('--log_level', default='INFO',
                       choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])
        p.add_argument('--library_path', default='~/Pictures')

    def _init_subclass(self):
        super()._init_subclass()
        self.log_level = self.cfg['log_level'].get(str)
        self.library_path = self.cfg['library_path'].get(str)

    def to_dict(self):
        base = super().to_dict()
        base.update({'log_level': self.log_level,
                     'library_path': self.library_path})
        return base

config = Confumo.expose(
    'cool_app',
    CoolAppConfig,
    globals(),
)

Running the application:

python cool_app/main.py --help

prints all flags exactly once.

Confumo collects add_args() methods across the config class MRO, so a subclass does not have to call super().add_args(p) to inherit parent flags. Calling super().add_args(p) is also safe: exact duplicate inherited argument registrations are ignored, while real conflicting option definitions still raise argparse errors.

4 · Access the config

from cool_app import config
print(config.library_path)

from confumo import Confumo
cfg = Confumo.get('cool_app', CoolAppConfig)

Both lines refer to the same singleton.

Safety checks

Confumo keys singleton instances by app_name, but it also validates the requested concrete config class on registry hits. If Confumo.get('demo', DemoConfig) created the singleton first, a later Confumo.get('demo', OtherConfig) raises ConfumoSingletonTypeError instead of returning a config object with the wrong shape. Requesting a base class remains valid when the existing singleton is an instance of that base class.

Confumo.expose(..., publish_to=(...)) also refuses to replace an existing Confumo-managed module proxy by default. Publish targets that are already imported are preflighted before the requested config singleton is constructed, so an unsafe cross-package alias is rejected before the importing package can run its own config bootstrap. This prevents one package from silently repointing another package's config, __getattr__, and __dir__ at an unrelated singleton. Use replace_existing=True only for an intentional compatibility shim where that replacement has been audited.

Precedence order

  1. CLI flags (--foo bar)
  2. Environment variables (COOL_APP__FOO=bar)
  3. YAML file (-c settings.yml) or default path
  4. Defaults hard-coded in your subclass

confuse handles deep-merging dicts and lists.

Persist the merged config

path = config.save_yaml()  # ~/.config/cool_app/cool_app_config.yaml (Linux)

The file contains the fully merged state for later inspection.

Testing helpers

config.copy() returns a detached clone whose built-in mutable containers and argparse namespace state do not alias the singleton. Runtime objects that cannot be copied, such as GUI widgets stored as leaf values, are preserved by reference.

License

This repository ships under 0BSD; see LICENSE.

Licensing / provenance notice

This repository may include AI-generated material and minimal human-authored material. To the extent any portion of this repository is not copyrightable, it is made available without restriction.

No third-party source or license texts are currently bundled in-tree. Any third-party material added later remains subject to its original terms.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

confumo-0.2.1.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

confumo-0.2.1-py3-none-any.whl (10.9 kB view details)

Uploaded Python 3

File details

Details for the file confumo-0.2.1.tar.gz.

File metadata

  • Download URL: confumo-0.2.1.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for confumo-0.2.1.tar.gz
Algorithm Hash digest
SHA256 bb56a70fe7beb18addc3b9b2ca187b9908e33b063f611d9f33acce5e0575b7ef
MD5 53bc57fbac3101418e5bb73236b6bb66
BLAKE2b-256 3df90926f250c22d5edb20041faba882a3aecf3b2fc675867bd31994cb2219c2

See more details on using hashes here.

File details

Details for the file confumo-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: confumo-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 10.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for confumo-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 05630fe72fb0c5452e0c69a46c496d469fc3c33d3852a49ef623c853d69abf59
MD5 5e6ecf36d20cd3cb6f5b4602edd4cd96
BLAKE2b-256 d0f1f4e5fbc6475d7a76f0d28b739b00f75ed7701ef23d432e0d5eabfcaebf09

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page