Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lzconfig — Lazy Configuration without instantiation

lz: Too lazy to type lazy

中文文档

Import and go. No init, no loader calls, no boilerplate.

import lzconfig as lz

# Attribute-style access
print(lz.database.host)                # → "localhost"
print(lz.database.credentials.user)    # → "admin"

# Dict-style access
print(lz['database']['host'])          # → "localhost"

# Mixed access
print(lz.database['port'])             # → 5432

# Safe access with defaults
print(lz.get('debug', False))          # → True

How It Works

At import time, lzconfig discovers your config file, parses it, interpolates environment variables, and replaces itself in sys.modules with the loaded configuration object. From then on, lz is your config.

Command-line --key value arguments are merged over the file, so the command line always wins. And if command-line arguments are present, no config file is needed at all.

Config File Resolution

  1. If LZCONFIG_FILE is set (and non-empty), that file is used. Relative paths are resolved against the current working directory.

  2. Otherwise, the current directory is scanned for the first match:

    Priority Filename
    1 lzconfig.yaml
    2 lzconfig.yml
    3 lzconfig.json
    4 lzconfig.toml
    5 lzconfig.ini
    6 lzconfig.cfg
    7 lzconfig.env
    8 lzconfig.xml
  3. If nothing is found and there are no --key value command-line arguments, ConfigNotFoundError is raised at import time.

Supported Formats

Format Extensions
YAML .yaml .yml
JSON .json
TOML .toml
INI .ini .cfg
.env .env
XML .xml

All formats work out of the box — no extras needed.

Environment Variable Interpolation

$VAR and ${VAR} references in config values are expanded at load time using os.path.expandvars:

# lzconfig.yaml
database:
  host: $DB_HOST
  password: ${DB_PASSWORD}

Undefined variables are left as literal text — no error is raised.

Command-Line Arguments

--key value and --key=value arguments are merged over the file-based configuration — the command line is the highest-priority source:

python app.py --database.host example.com --port 8080 --debug true
import lzconfig as lz

lz.database.host  # "example.com" — overrides the config file
lz.port           # 8080 — an int, not a string
lz.debug          # True — a bool

Rules:

  • Dotted keys build nested structure: --database.host x sets lz.database.host.
  • Values are parsed with JSON when possible (--port 5432 → int, --debug true → bool, --tags '["a","b"]' → list); otherwise they stay strings (--zip 01234"01234").
  • A bare --key (no value) is treated as True.
  • Only -- options are consumed; everything else is left in sys.argv untouched, and a bare -- ends option parsing.
  • If command-line arguments are present, no config file is necessary, the config will be built from the command line alone.
  • If neither a config file nor command-line arguments exist, ConfigNotFoundError is raised.

Access Patterns

Pattern Example
Attribute chain lz.a.b.c
Dict chain lz['a']['b']['c']
Mixed lz.a['b'].c
List index lz['items'][0].name
Membership 'key' in lz
Safe get lz.get('key', default)
Keys lz.keys()
Length len(lz)
Iteration for k in lz: ...
Attribute write lz.debug = True
Dict write lz['database']['port'] = 8080
Delete key del lz.debug / del lz['debug']

The config object is mutable — attribute and dict-style writes update the underlying data in place, and nested values share the same storage (lz.database.host = '...' is visible through lz['database']['host']).

Key / Method Collision

If a config key happens to have the same name as a ConfigObject method (e.g., get, items, keys):

  • Attribute access (lz.items) returns the method.
  • Dict access (lz['items']) always returns the config value.

This is a deliberate trade-off. When in doubt, use [] — it always works. The same rule applies to writes: lz.items = [...] still stores the config value, but reading lz.items returns the method.

Error Handling

Exception When
ConfigNotFoundError No config file found and no --key value arguments present
ConfigParseError File found but cannot be parsed
ConfigKeyError Accessing a non-existent key

All exceptions inherit from ConfigError and can be imported directly:

from lzconfig import ConfigError, ConfigNotFoundError, ConfigKeyError

License

MIT

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages