
Research
Malicious npm Package Brand-Squats TanStack to Exfiltrate Environment Variables
A brand-squatted TanStack npm package used postinstall scripts to steal .env files and exfiltrate developer secrets to an attacker-controlled endpoint.
python-simpleconf
Advanced tools
Simple configuration management for python
# 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]
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())
from simpleconf import Config
conf = Config.load({'a': 1, 'b': {'c': 2}})
# conf.a == 1
# conf.b.c == 2
.ini/.cfg/.config (parsed by iniconfig).
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."{'a': 1}" will be loaded as conf.a = 1.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
.env fileconfig.env
# config.env
default_a=1
from simpleconf import ProfileConfig
conf = ProfileConfig.load('config.env')
# conf.a == 1
# config.ini
[default]
a = 1
from simpleconf import ProfileConfig
conf = ProfileConfig.load('config.ini')
# conf.a == 1
config.json
{
"default": {
"a": 1
}
}
from simpleconf import ProfileConfig
conf = ProfileConfig.load('config.json')
# conf.a == 1
from os import environ
from simpleconf import ProfileConfig
environ['XXX_DEFAULT_A'] = '1'
conf = ProfileConfig.load('XXX.osenv')
# conf.a == 1
# config.toml
[default]
a = 1
from simpleconf import ProfileConfig
conf = ProfileConfig.load('config.toml')
# conf.a == 1
# config.yaml
default:
a: 1
from simpleconf import ProfileConfig
conf = ProfileConfig.load('config.yaml')
# conf.a == 1
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
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:
from os import environ
from simpleconf import Config
environ['XXX_A'] = '@int:1'
conf = Config.load('XXX.osenv')
# conf.a == 1 # int
@float:1.0 -> 1.0
@bool:true -> True
@bool:false -> False
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:{"a": 1} -> {"a": 1}
@toml:a = 1 -> {"a": 1}
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
Instead of using a special file extension, you can embed a loader directive in the first line 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
FAQs
Simple configuration management with python.
We found that python-simpleconf demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A brand-squatted TanStack npm package used postinstall scripts to steal .env files and exfiltrate developer secrets to an attacker-controlled endpoint.

Research
Compromised SAP CAP npm packages download and execute unverified binaries, creating urgent supply chain risk for affected developers and CI/CD environments.

Company News
Socket has acquired Secure Annex to expand extension security across browsers, IDEs, and AI tools.