Skip to main content

simpleconf

Simple configuration management for python

Installation

# released version
pip install python-simpleconf

# Install support for ini
pip install python-simpleconf[ini]

# Install support for dotenv
pip install python-simpleconf[dotenv]

# Install support for yaml
pip install python-simpleconf[yaml]

# Install support for toml
pip install python-simpleconf[toml]

# Install support for all supported formats
pip install python-simpleconf[all]

Features

  • Multiple formats supported
  • Type casting
  • Profile support
  • Simple APIs
  • Async loading support
  • Templated configuration files support (jinja2 and liquid)

Usage

Loading configurations

import asyncio
from simpleconf import Config


async def main():
  # Load a single file
  conf = Config.load('~/xxx.ini')
  # load multiple files, later files override previous ones
  conf = Config.load(
    '~/xxx.ini', '~/xxx.env', '~/xxx.yaml', '~/xxx.toml',
    '~/xxx.json', 'simpleconf.osenv', {'a': 3}
  )

  # Load a single file with a different loader
  conf = Config.load('~/xxx.ini', loader="toml")

  # Async loading
  conf = await Config.a_load('~/xxx.ini')

if __name__ == "__main__":
  asyncio.run(main())

Accessing configuration values

from simpleconf import Config

conf = Config.load({'a': 1, 'b': {'c': 2}})
# conf.a == 1
# conf.b.c == 2

Supported formats

  • .ini/.cfg/.config (parsed by iniconfig).
    • For confiurations without profiles, an ini-like configuration like must have a default (case-insensitive) section.
  • .env (using python-dotenv). A file with environment variables.
  • .yaml/.yml (using pyyaml). A file with YAML data.
  • .toml (using rtoml). A file with TOML data.
  • .json (using json). A file with JSON data.
  • XXX.osenv: System environment variables with prefix XXX_ (case-sensitive) is used.
    • XXX_A=1 will be loaded as conf.A = 1.
  • python dictionary.
  • Strings format of the above formats are also supported.
    • "{'a': 1}" will be loaded as conf.a = 1.

Profile support

Loading configurations

Loading dictionaries
from simpleconf import ProfileConfig

conf = ProfileConfig.load({'default': {'a': 1})
# conf.a == 1

# Asynchronous loading
# conf = await ProfileConfig.a_load({'default': {'a': 1})
# conf.a == 1
Loading a .env file

config.env

# config.env
default_a=1
from simpleconf import ProfileConfig

conf = ProfileConfig.load('config.env')
# conf.a == 1
Loading ini-like configuration files
# config.ini
[default]
a = 1
from simpleconf import ProfileConfig

conf = ProfileConfig.load('config.ini')
# conf.a == 1
Loading JSON files

config.json

{
  "default": {
    "a": 1
  }
}
from simpleconf import ProfileConfig

conf = ProfileConfig.load('config.json')
# conf.a == 1
Loading system environment variables
from os import environ
from simpleconf import ProfileConfig

environ['XXX_DEFAULT_A'] = '1'

conf = ProfileConfig.load('XXX.osenv')
# conf.a == 1
Loading TOML files
# config.toml
[default]
a = 1
from simpleconf import ProfileConfig

conf = ProfileConfig.load('config.toml')
# conf.a == 1
Loading YAML files
# config.yaml
default:
  a: 1
from simpleconf import ProfileConfig

conf = ProfileConfig.load('config.yaml')
# conf.a == 1

Switching profile

from simpleconf import ProfileConfig

conf = ProfileConfig.load(
   {'default': {'a': 1, 'b': 2}, 'dev': {'a': 3}, 'prod': {'a': 4}}
)
# conf.a == 1; conf.b == 2
# ProfileConfig.profiles(conf) == ['default', 'dev', 'prod']
# ProfileConfig.pool(conf) == {'default': {'a': 1, 'b': 2}, 'dev': {'a': 3}, 'prod': {'a': 4}}
# ProfileConfig.current_profile(conf) == 'default'
# ProfileConfig.base_profile(conf) == 'default'

ProfileConfig.use_profile(conf, 'dev')
# conf.a == 3; conf.b == 2
# ProfileConfig.current_profile(conf) == 'dev'
# ProfileConfig.base_profile(conf) == 'default'

# use a different base profile
ProfileConfig.use_profile(conf, 'prod', base='dev')
# conf.a == 4   # No 'b' in conf
# ProfileConfig.current_profile(conf) == 'prod'
# ProfileConfig.base_profile(conf) == 'dev'

# Copy configuration instead of inplace modification
conf2 = ProfileConfig.use_profile(conf, 'dev', copy=True)
# conf2 is not conf
# conf2.a == 3; conf2.b == 2

# Use a context manager
with ProfileConfig.use_profile(conf2, 'default'):
    conf2.a == 3
    conf2.b == 2
# conf2.a == 3; conf2.b == 2

Type casting

For configuration formats with type support, including dictionary, no type casting is done by this library, except that for TOML files.

TOML does not support None value in python. We use rtoml library to parse TOML files, which dumps None as "null". So a null_caster is used to cast "null" to None.

A none_caster is also enabled for TOML files, a pure string of "@none" is casted to None.

For other formats, following casters are supported:

Int caster

from os import environ
from simpleconf import Config

environ['XXX_A'] = '@int:1'

conf = Config.load('XXX.osenv')
# conf.a == 1 # int

Float caster

@float:1.0 -> 1.0

Bool caster

@bool:true -> True @bool:false -> False

Python caster

Values are casted by ast.literal_eval().

"@python:1" => 1  # or
"@py:1" => 1
"@py:1.0` -> `1.0`
"@py:[1, 2, 3]" => [1, 2, 3]

JSON caster

@json:{"a": 1} -> {"a": 1}

TOML caster

@toml:a = 1 -> {"a": 1}

Templated configuration files

jinja2 and liquid templating engines are supported. The templating engine is determined by the file extension, which can be either the primary or secondary suffix. For example, config.toml.j2 and config.j2.toml are both treated as TOML files with Jinja2 templating.

config.toml.j2

a = {{ 1 + 2 }}
from simpleconf import Config

conf = Config.load('config.toml.j2')
# conf.a == 3

config.liq.toml

{% for i in range(1, 3) %}
[section{{i}}]
a = {{i}}
{% endfor %}
from simpleconf import Config

conf = Config.load('config.liq.toml')
# conf.section1.a == 1
# conf.section2.a == 2

Loader directive

Instead of using a special file extension, you can embed a loader directive in the first lines of a configuration file as a comment. This allows a plain config.toml to be processed by the Liquid engine without renaming the file.

The directive format is:

# simpleconf-loader: <loader>

Supported comment prefixes: #, ;, // (case-insensitive).

The <loader> value can be:

Value Meaning
liq or liquid Use the Liquid loader for this file's format
j2, jinja, or jinja2 Use the Jinja2 loader for this file's format
A full extension (e.g. toml.liq) Use the exact loader specified

Example — Liquid in a plain .toml file:

config.toml

# simpleconf-loader: liq
{% set x = 10 %}
[default]
a = {{ 1 + 1 }}
b = {{ x + 2 }}
from simpleconf import Config

conf = Config.load('config.toml')
# conf.default.a == 2
# conf.default.b == 12

Example — Jinja2 in a plain .yaml file:

config.yaml

# simpleconf-loader: j2
default:
  a: {{ 1 + 1 }}
from simpleconf import Config

conf = Config.load('config.yaml')
# conf.default.a == 2

Loadenv directive

You will need python-dotenv installed to use the loadenv directive. You can install it with:

pip install python-simpleconf[toml,env]

if you only need TOML and dotenv support, or

pip install python-simpleconf[all]

if you want all supported formats.

You can also embed a # simpleconf-loadenv directive in the first few lines of a configuration file to load environment variables from a .env file. This allows you to reference environment variables directly in your config values using $env:VAR syntax, and makes them available as env in Jinja2/Liquid templates via {{ env.VAR }} or {{ env["VAR"] }}.

The directive format is:

# simpleconf-loadenv
# simpleconf-loadenv: /path/to/.env

When no path is given, ./.env is loaded (relative to the config file's directory).

Supported comment prefixes: #, ;, // (case-insensitive).

Example — using $env:VAR references:

.env

DB_HOST=localhost
DB_PORT=@int:5432

config.yaml

# simpleconf-loadenv
db:
  host: $env:DB_HOST
  port: $env:DB_PORT
from simpleconf import Config

conf = Config.load('config.yaml')
# conf.db.host == 'localhost'
# conf.db.port == 5432  # @int: cast to int

The $env:VAR syntax works in all supported formats (YAML, TOML, INI, JSON, .env). In formats that require quoted strings (TOML), wrap the reference in quotes: "$env:DB_HOST".

Lookup order: the loaded .env file is checked first, then os.environ as a fallback.

Modifiers — controlling what happens when a variable is not found

The $env: syntax supports optional modifiers to control the behavior when a variable is not found:

Syntax Behavior when VAR not found
$env:VAR Default — raises ValueError
$env:VAR:required Explicit form — raises ValueError
$env:VAR:optional-asis Keeps the literal $env:VAR string unchanged
$env:VAR:optional-empty Resolves to an empty string ""
$env:VAR:default:<value> Resolves to <value> instead

When found, the environment variable's value always wins over the default. Default values go through the same casting as env values, so cast prefixes like @int: work there too (e.g. $env:PORT:default:@int:8080 resolves to the integer 8080). The default value itself may contain colons (e.g. $env:URL:default:http://localhost:8080).

Example — using modifiers:

.env

DB_HOST=localhost

config.yaml

# simpleconf-loadenv
db:
  host: $env:DB_HOST
  port: $env:DB_PORT:optional-asis   # keeps "$env:DB_PORT" as-is when not found
  timeout: $env:TIMEOUT:optional-empty  # becomes "" when not found
  user: $env:DB_USER:default:admin   # becomes "admin" when not found
from simpleconf import Config

conf = Config.load('config.yaml')
# conf.db.host == 'localhost'
# conf.db.port == '$env:DB_PORT'
# conf.db.timeout == ''
# conf.db.user == 'admin'

Example — using env in templates:

.env

DB_HOST=localhost
DB_PORT=5432

config.toml

# simpleconf-loadenv
# simpleconf-loader: liq
[default]
url = "{{ env.DB_HOST }}:{{ env.DB_PORT }}"
from simpleconf import Config

conf = Config.load('config.toml')
# conf.default.url == 'localhost:5432'

Both directives (simpleconf-loader and simpleconf-loadenv) can coexist in the same file on different lines. The order does not matter.

Download files

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

Source Distribution

python_simpleconf-0.9.6.tar.gz (231.2 kB view details)

Uploaded Source

Built Distribution

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

python_simpleconf-0.9.6-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file python_simpleconf-0.9.6.tar.gz.

File metadata

  • Download URL: python_simpleconf-0.9.6.tar.gz
  • Upload date:
  • Size: 231.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for python_simpleconf-0.9.6.tar.gz
Algorithm Hash digest
SHA256 3bdb44d4013068926eb5997788261d34b1fb3da881bc547b277621dd48951d8e
MD5 12e2513d3899f0b8c5c043110eb6d573
BLAKE2b-256 18b9134ba938422f1f090914af91f785591df256fb1270fb9e353ab38ba67295

See more details on using hashes here.

File details

Details for the file python_simpleconf-0.9.6-py3-none-any.whl.

File metadata

  • Download URL: python_simpleconf-0.9.6-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for python_simpleconf-0.9.6-py3-none-any.whl
Algorithm Hash digest
SHA256 676631fa0a2dd0f13ebe248bbc35f9473b4641a2f70abfe584336a3bd202612d
MD5 d39f0b91e175a6f09dece090030a304b
BLAKE2b-256 6b48273af7aa3e54258b7cdb60762e401032bf142c37537583b1064bf339b6a6

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.9.6 This release

2 files

0.9.5

2 files

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.9

2 files

0.5.8

2 files

0.5.7

2 files

0.5.6

2 files

0.5.5

2 files

0.5.4

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.0.12

2 files

0.0.11

2 files

0.0.10

2 files

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page