Environment-aware configuration management for Python packages using INI
files with automatic type conversion to basic types (int, float, None,
bool, str). Any variables with multiple comma-separated values will be
converted to a list. Handles multi-environment setups (i.e. dev/testing)
with automatic file discovery across standard configuration locations.
**Environment variables override INI values** (i.e. prod) when they have
the same name (or UPPERCASE name) as variables in the ``settings.ini``
file. You can comment out any variables in the settings.ini file with a
leading ``#``.
Tested for Python 3.5 - 3.13.
Example settings.ini
--------------------
.. code:: ini
[default]
something = 100
# other = 250
[dev]
redis_url = redis://localhost:6379/1
something = 500
[test]
redis_url = redis://localhost:6379/9
things = none, true, false, 1, 2.5, dogs
something_else = 2.0
Searches ``~/.config/<package>/settings.ini``,
``/etc/<package>/settings.ini``, ``/tmp/<package>/settings.ini``, then
``./settings.ini``. Copies default settings from package if missing. See
`Setup in your
package <https://github.com/kenjyco/settings-helper/blob/master/README.md#setup-in-your-package>`__
below to define a default settings.ini file for your package.
You must include at least one section header in your settings.ini file
(like ``[default]``). The configparser will raise a
MissingSectionHeaderError if no headers are defined. The only special
header is **``[default]``**. If you have any additional section headers,
each parsed section will only contain things defined in that section,
plus anything defined in the ``[default]`` section.
Install
-------
::
pip install settings-helper
QuickStart
----------
.. code:: python
import settings_helper as sh
# Get all settings by section
settings = sh.get_all_settings(__name__)
# Returns:
# {
# 'default': {'something': 100},
# 'dev': {'redis_url': 'redis://localhost:6379/1', 'something': 500},
# 'test': {'redis_url': 'redis://localhost:6379/9', 'something': 100, 'something_else': 2.0,
# 'things': [None, True, False, 1, 2.5, 'dogs']}
# }
# Get environment-specific settings (APP_ENV defaults to 'dev')
SETTINGS = sh.get_all_settings(__name__).get(sh.APP_ENV, {})
redis_url = SETTINGS.get('redis_url')
something = SETTINGS.get('something', 100)
# Alternative: use settings getter factory
get_setting = sh.settings_getter(__name__)
redis_url = get_setting('redis_url')
something = get_setting('something', 100)
# All values are automatically converted: 'true' → True, '100' → 100, 'none' → None
# Lists are automatically parsed: 'a,b,c' → ['a', 'b', 'c']
Note that when using the older ``settings_getter``, the **``APP_ENV``**
environment variable is used to determine the section of the
setttings.ini file to get the value from. This value defaults to ``dev``
if not set. If the variable is not defined in the section, it will pull
the value from the ``[default]`` section. If the variable is not defined
in the default section, it will return the optional fallback value.
Setup for a one-off script
--------------------------
Create a ``settings.ini`` file next to your script with at least one
section header in square brackets (like ``[my stuff]``).
::
[my stuff]
something = 100
things = none, true, false, 1, 2.5, dogs and cats, grapes
# other = 500
Use the simple ``get_all_settings`` function to get a dict of all
settings by section header.
::
import settings_helper as sh
settings = sh.get_all_settings()
For our settings.ini file example, the settings dict from
``get_all_settings()`` would be the following:
::
{
'my stuff': {
'something': 100,
'things': [None, True, False, 1, 2.5, 'dogs and cats', 'grapes']
}
}
When dealing with settings where values are numbers, but you don’t want
them converted (i.e. version numbers like “3.10”), you can set kwarg
``keep_num_as_string`` to ``True`` when calling ``get_all_settings`` (or
``settings_getter``).
::
import settings_helper as sh
settings = sh.get_all_settings(keep_num_as_string=True)
For our settings.ini file example, the settings dict from
``get_all_settings(keep_num_as_string=True)`` would be the following:
::
{
'my stuff': {
'something': '100',
'things': [None, True, False, '1', '2.5', 'dogs and cats', 'grapes']
}
}
Setup in your package
---------------------
Create a default/sample ``settings.ini`` file in the module directory of
your package, with a ``[default]`` section and any other ``[sections]``
you want (i.e. app environments)
::
[default]
something = 100
[dev]
redis_url = redis://localhost:6379/1
something = 500
[test]
redis_url = redis://localhost:6379/9
things = none, true, false, 1, 2.5, dogs
something_else = 2.0
For this settings.ini file example, the settings dict from
``get_all_settings()`` would be the following:
::
{
'dev': {
'something': 500,
'redis_url': 'redis://localhost:6379/1'
},
'default': {
'something': 100
},
'test': {
'something': 100,
'something_else': 2.0,
'redis_url': 'redis://localhost:6379/9',
'things': [None, True, False, 1, 2.5, 'dogs']
}
}
Create a ``MANIFEST.in`` file in your package directory with the
following
::
include settings.ini
Update the ``setup.py`` file of the package to include the
``setting.ini`` file and add ``settings-helper`` to ``install_requires``
list
::
from setuptools import setup, find_packages
setup(
name='package-name',
version='0.0.1',
...
packages=find_packages(),
install_requires=[
'settings-helper',
...
],
include_package_data=True,
package_dir={'': '.'},
package_data={
'': ['*.ini'],
},
...
)
Note, your package directory tree will be something like the following
::
package-name
├── .gitignore
├── LICENSE.txt
├── MANIFEST.in
├── README.md
├── README.rst
├── package_name/
│ ├── __init__.py
│ └── settings.ini
└── setup.py
Tip
~~~
In your ``<package-name>/tests/__init__.py`` file, add the following so
the ``test`` section of settings is automatically used
::
import os
os.environ['APP_ENV'] = 'test'
API Overview
------------
Configuration Loading
~~~~~~~~~~~~~~~~~~~~~
- **``get_all_settings(module_name='', keep_num_as_string=False)``** -
Return all settings by section
- ``module_name``: Package name for settings discovery
- ``keep_num_as_string``: Preserve numeric strings without
conversion
- Returns: Dictionary with section names as keys
- Internal calls: ``ih.from_string()``,
``ih.string_to_converted_list()``
- **``settings_getter(module_name, section=APP_ENV, keep_num_as_string=False)``**
- Create setting getter function
- ``module_name``: Package name for settings discovery
- ``section``: Configuration section to use
- ``keep_num_as_string``: Preserve numeric strings without
conversion
- Returns: Function for retrieving individual settings
- Internal calls: None
File Management
~~~~~~~~~~~~~~~
- **``get_settings_file(module_name='', copy_default_if_missing=True, exception=True)``**
- Locate settings file
- ``module_name``: Package name for discovery (empty for current
directory)
- ``copy_default_if_missing``: Copy default settings if missing
- ``exception``: Raise exception if not found
- Returns: Path to settings.ini file
- Internal calls: ``get_default_settings_file()``
- **``get_default_settings_file(module_name, exception=True)``** - Find
package default settings
- ``module_name``: Package name to search
- ``exception``: Raise exception if not found
- Returns: Path to default settings.ini in package
- Internal calls: None
- **``sync_settings_file(module_name)``** - Compare settings with
vimdiff
- ``module_name``: Package name
- Returns: None (launches vimdiff if files differ)
- Internal calls: ``get_settings_file()``,
``get_default_settings_file()``, ``bh.run_output()``, ``bh.run()``
Raw data
{
"_id": null,
"home_page": "https://github.com/kenjyco/settings-helper",
"name": "settings-helper",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "settings, config, environment variables, ini, ini file, ini parser, helper, kenjyco",
"author": "Ken",
"author_email": "kenjyco@gmail.com",
"download_url": "https://github.com/kenjyco/settings-helper/tarball/v0.0.18",
"platform": null,
"description": "Environment-aware configuration management for Python packages using INI\nfiles with automatic type conversion to basic types (int, float, None,\nbool, str). Any variables with multiple comma-separated values will be\nconverted to a list. Handles multi-environment setups (i.e.\u00a0dev/testing)\nwith automatic file discovery across standard configuration locations.\n**Environment variables override INI values** (i.e.\u00a0prod) when they have\nthe same name (or UPPERCASE name) as variables in the ``settings.ini``\nfile. You can comment out any variables in the settings.ini file with a\nleading ``#``.\n\nTested for Python 3.5 - 3.13.\n\nExample settings.ini\n--------------------\n\n.. code:: ini\n\n [default]\n something = 100\n # other = 250\n\n [dev]\n redis_url = redis://localhost:6379/1\n something = 500\n\n [test]\n redis_url = redis://localhost:6379/9\n things = none, true, false, 1, 2.5, dogs\n something_else = 2.0\n\nSearches ``~/.config/<package>/settings.ini``,\n``/etc/<package>/settings.ini``, ``/tmp/<package>/settings.ini``, then\n``./settings.ini``. Copies default settings from package if missing. See\n`Setup in your\npackage <https://github.com/kenjyco/settings-helper/blob/master/README.md#setup-in-your-package>`__\nbelow to define a default settings.ini file for your package.\n\nYou must include at least one section header in your settings.ini file\n(like ``[default]``). The configparser will raise a\nMissingSectionHeaderError if no headers are defined. The only special\nheader is **``[default]``**. If you have any additional section headers,\neach parsed section will only contain things defined in that section,\nplus anything defined in the ``[default]`` section.\n\nInstall\n-------\n\n::\n\n pip install settings-helper\n\nQuickStart\n----------\n\n.. code:: python\n\n import settings_helper as sh\n\n # Get all settings by section\n settings = sh.get_all_settings(__name__)\n # Returns:\n # {\n # 'default': {'something': 100},\n # 'dev': {'redis_url': 'redis://localhost:6379/1', 'something': 500},\n # 'test': {'redis_url': 'redis://localhost:6379/9', 'something': 100, 'something_else': 2.0,\n # 'things': [None, True, False, 1, 2.5, 'dogs']}\n # }\n\n # Get environment-specific settings (APP_ENV defaults to 'dev')\n SETTINGS = sh.get_all_settings(__name__).get(sh.APP_ENV, {})\n redis_url = SETTINGS.get('redis_url')\n something = SETTINGS.get('something', 100)\n\n # Alternative: use settings getter factory\n get_setting = sh.settings_getter(__name__)\n redis_url = get_setting('redis_url')\n something = get_setting('something', 100)\n\n # All values are automatically converted: 'true' \u2192 True, '100' \u2192 100, 'none' \u2192 None\n # Lists are automatically parsed: 'a,b,c' \u2192 ['a', 'b', 'c']\n\nNote that when using the older ``settings_getter``, the **``APP_ENV``**\nenvironment variable is used to determine the section of the\nsetttings.ini file to get the value from. This value defaults to ``dev``\nif not set. If the variable is not defined in the section, it will pull\nthe value from the ``[default]`` section. If the variable is not defined\nin the default section, it will return the optional fallback value.\n\nSetup for a one-off script\n--------------------------\n\nCreate a ``settings.ini`` file next to your script with at least one\nsection header in square brackets (like ``[my stuff]``).\n\n::\n\n [my stuff]\n something = 100\n things = none, true, false, 1, 2.5, dogs and cats, grapes\n # other = 500\n\nUse the simple ``get_all_settings`` function to get a dict of all\nsettings by section header.\n\n::\n\n import settings_helper as sh\n\n settings = sh.get_all_settings()\n\nFor our settings.ini file example, the settings dict from\n``get_all_settings()`` would be the following:\n\n::\n\n {\n 'my stuff': {\n 'something': 100,\n 'things': [None, True, False, 1, 2.5, 'dogs and cats', 'grapes']\n }\n }\n\nWhen dealing with settings where values are numbers, but you don\u2019t want\nthem converted (i.e.\u00a0version numbers like \u201c3.10\u201d), you can set kwarg\n``keep_num_as_string`` to ``True`` when calling ``get_all_settings`` (or\n``settings_getter``).\n\n::\n\n import settings_helper as sh\n\n settings = sh.get_all_settings(keep_num_as_string=True)\n\nFor our settings.ini file example, the settings dict from\n``get_all_settings(keep_num_as_string=True)`` would be the following:\n\n::\n\n {\n 'my stuff': {\n 'something': '100',\n 'things': [None, True, False, '1', '2.5', 'dogs and cats', 'grapes']\n }\n }\n\nSetup in your package\n---------------------\n\nCreate a default/sample ``settings.ini`` file in the module directory of\nyour package, with a ``[default]`` section and any other ``[sections]``\nyou want (i.e.\u00a0app environments)\n\n::\n\n [default]\n something = 100\n\n [dev]\n redis_url = redis://localhost:6379/1\n something = 500\n\n [test]\n redis_url = redis://localhost:6379/9\n things = none, true, false, 1, 2.5, dogs\n something_else = 2.0\n\nFor this settings.ini file example, the settings dict from\n``get_all_settings()`` would be the following:\n\n::\n\n {\n 'dev': {\n 'something': 500,\n 'redis_url': 'redis://localhost:6379/1'\n },\n 'default': {\n 'something': 100\n },\n 'test': {\n 'something': 100,\n 'something_else': 2.0,\n 'redis_url': 'redis://localhost:6379/9',\n 'things': [None, True, False, 1, 2.5, 'dogs']\n }\n }\n\nCreate a ``MANIFEST.in`` file in your package directory with the\nfollowing\n\n::\n\n include settings.ini\n\nUpdate the ``setup.py`` file of the package to include the\n``setting.ini`` file and add ``settings-helper`` to ``install_requires``\nlist\n\n::\n\n from setuptools import setup, find_packages\n\n setup(\n name='package-name',\n version='0.0.1',\n ...\n packages=find_packages(),\n install_requires=[\n 'settings-helper',\n ...\n ],\n include_package_data=True,\n package_dir={'': '.'},\n package_data={\n '': ['*.ini'],\n },\n ...\n )\n\nNote, your package directory tree will be something like the following\n\n::\n\n package-name\n \u251c\u2500\u2500 .gitignore\n \u251c\u2500\u2500 LICENSE.txt\n \u251c\u2500\u2500 MANIFEST.in\n \u251c\u2500\u2500 README.md\n \u251c\u2500\u2500 README.rst\n \u251c\u2500\u2500 package_name/\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 settings.ini\n \u2514\u2500\u2500 setup.py\n\nTip\n~~~\n\nIn your ``<package-name>/tests/__init__.py`` file, add the following so\nthe ``test`` section of settings is automatically used\n\n::\n\n import os\n\n os.environ['APP_ENV'] = 'test'\n\nAPI Overview\n------------\n\nConfiguration Loading\n~~~~~~~~~~~~~~~~~~~~~\n\n- **``get_all_settings(module_name='', keep_num_as_string=False)``** -\n Return all settings by section\n\n - ``module_name``: Package name for settings discovery\n - ``keep_num_as_string``: Preserve numeric strings without\n conversion\n - Returns: Dictionary with section names as keys\n - Internal calls: ``ih.from_string()``,\n ``ih.string_to_converted_list()``\n\n- **``settings_getter(module_name, section=APP_ENV, keep_num_as_string=False)``**\n - Create setting getter function\n\n - ``module_name``: Package name for settings discovery\n - ``section``: Configuration section to use\n - ``keep_num_as_string``: Preserve numeric strings without\n conversion\n - Returns: Function for retrieving individual settings\n - Internal calls: None\n\nFile Management\n~~~~~~~~~~~~~~~\n\n- **``get_settings_file(module_name='', copy_default_if_missing=True, exception=True)``**\n - Locate settings file\n\n - ``module_name``: Package name for discovery (empty for current\n directory)\n - ``copy_default_if_missing``: Copy default settings if missing\n - ``exception``: Raise exception if not found\n - Returns: Path to settings.ini file\n - Internal calls: ``get_default_settings_file()``\n\n- **``get_default_settings_file(module_name, exception=True)``** - Find\n package default settings\n\n - ``module_name``: Package name to search\n - ``exception``: Raise exception if not found\n - Returns: Path to default settings.ini in package\n - Internal calls: None\n\n- **``sync_settings_file(module_name)``** - Compare settings with\n vimdiff\n\n - ``module_name``: Package name\n - Returns: None (launches vimdiff if files differ)\n - Internal calls: ``get_settings_file()``,\n ``get_default_settings_file()``, ``bh.run_output()``, ``bh.run()``\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Helpers to get specific settings from a particular section of a settings.ini file",
"version": "0.0.18",
"project_urls": {
"Download": "https://github.com/kenjyco/settings-helper/tarball/v0.0.18",
"Homepage": "https://github.com/kenjyco/settings-helper"
},
"split_keywords": [
"settings",
" config",
" environment variables",
" ini",
" ini file",
" ini parser",
" helper",
" kenjyco"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "611ad403fa65ae9ce96a36a92c5d394a5870a9e04a2c9feb02ccb8bd7170dd6a",
"md5": "8d57bc32ba9dd1f94c7b1e8d09adf11e",
"sha256": "adbe92c69fef9bda3be704f5ae99308cd775dc58cc852c1d49c9819a6a8d18b2"
},
"downloads": -1,
"filename": "settings_helper-0.0.18-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8d57bc32ba9dd1f94c7b1e8d09adf11e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 8470,
"upload_time": "2025-08-08T17:24:37",
"upload_time_iso_8601": "2025-08-08T17:24:37.777556Z",
"url": "https://files.pythonhosted.org/packages/61/1a/d403fa65ae9ce96a36a92c5d394a5870a9e04a2c9feb02ccb8bd7170dd6a/settings_helper-0.0.18-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-08 17:24:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "kenjyco",
"github_project": "settings-helper",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "bg-helper",
"specs": []
},
{
"name": "input-helper",
"specs": []
}
],
"lcname": "settings-helper"
}