Skip to main content

ConfigParser with environment variable and direct assignment overrides

Project description

ConfigParser Override

Version Build Status

ConfigParserOverride enhances the ConfigParser by allowing you to override options from a configuration file or add new options using; environment variables and directly assigned key-value arguments.

NOTE: This package only depends on the Python Standard Library!

Features

  • Read configuration from one or more files.
  • Override configuration options with environment variables.
  • Override configuration options with directly assigned arguments.
  • Optional environment variable prefix support.
  • Convert configuration objects to a dataclass and cast the values to predefined datatypes.

Install

pip install configparser-override

Usage

Example of how to use ConfigParserOverride:

Example config.ini File

[DEFAULT]
default_key1 = default_value1
default_key2 = default_value2

[section1]
key1 = value1
key2 = value2

[section2]
key3 = value3
key4 = value4

Python Code

import os

from configparser_override import ConfigParserOverride

# Optionally set environment variables for overriding
os.environ["MYAPP_DEFAULT_KEY1"] = "overridden_default_value1"
os.environ["MYAPP_SECTION1__KEY1"] = "overridden_value1"
os.environ["MYAPP_SECTION2__KEY3"] = "overridden_value3"

# Initialize the parser with an optional environment variable prefix and
# overrides from direct assignments.
parser = ConfigParserOverride(
    env_prefix="MYAPP_",
    # Sections & options are case insensitive by default
    SECTION2__KEY4="direct_override_value4",
    section2__key5="direct_override_value5",
)

# Read configuration from a file
config = parser.read(filenames="config.ini")

# Access the configuration
print(config.defaults()["default_key1"])  # Output: overridden_default_value1
print(config.defaults()["default_key2"])  # Output: default_value2
print(config["section1"]["key1"])  # Output: overridden_value1
print(config["section1"]["key2"])  # Output: value2
print(config["section2"]["key3"])  # Output: overridden_value3
print(config["section2"]["key4"])  # Output: direct_override_value4
print(config["section2"]["key5"])  # Output: direct_override_value5

Configuration source precedence

Configuration options can be overridden in three ways. This is the order of precedence:

  1. Directly assigned arguments during initialization of the ConfigParserOverride class.
  2. Environment variables.
  3. Configuration files.

Environment variable configuration

Override configuration options using environment variables with the following format:

  • No Prefix:

    • For DEFAULT section: [OPTION]
    • For other sections: [SECTION]__[OPTION]
  • With Prefix (MYAPP_ as an example):

    • For DEFAULT section: [PREFIX][OPTION]
    • For other sections: [PREFIX][SECTION]__[OPTION]

Example:

  • To override key1 in section1 with prefix MYAPP_, use MYAPP_SECTION1__KEY1.

Convert to a Dataclass and Validate Data Types

The library features a ConfigConverter class, which enables the conversion of configuration data into a dataclass instance. This functionality is particularly useful for ensuring that the configuration adheres to the expected format, since it tries to cast the option in the config to the types in the dataclass. Hence, it also allows you to take advantage of various typing frameworks and tools, such as integrations with your text editor, providing enhanced validation and code assistance.

Example

from dataclasses import dataclass
from typing import Optional

from configparser_override import ConfigParserOverride


@dataclass
class Section1:
    key1: int
    key2: list[str]
    key3: Optional[str] = None


@dataclass
class ExampleConfig:
    section1: Section1


# Initialize the parser with overrides
parser = ConfigParserOverride(
    section1__key1="42", section1__key2="['item1', 'item2']"
)

# Read configuration from **optional** file
parser.read(filenames=[])

# Convert to dataclass
config_as_dataclass = parser.to_dataclass(ExampleConfig)
print(config_as_dataclass.section1.key1)  # Output: 42
print(type(config_as_dataclass.section1.key1))  # Output: <class 'int'>
print(config_as_dataclass.section1.key2)  # Output: ['item1', 'item2']
print(type(config_as_dataclass.section1.key2))  # Output: <class 'list'>
print(config_as_dataclass.section1.key3)  # Output: None

Data Types

Supported data types are:

  • String
  • Integer
  • Bool
  • Float
  • Complex
  • Bytes

Collections (nesting is supported):

  • List
  • Dict
  • Set
  • Tuple

Others:

  • None
  • Optional | Option does not need to exist in config
  • Union | Tries to cast until successful, in the order the types are specified
  • Any | no type cast

Platform Dependency

Different operating systems handle environment variables differently. Linux is case sensitive while Windows is not. See os.environ docs. Hence, it is safest to always use capitalized environment variables to avoid any unexpected behavior.

Recommendation

In order to avoid any unanticipated issues and make your code safe to run on any platform, follow these rules:

Element Recommended Case
Environment variables UPPERCASE
Environment variable prefix UPPERCASE
DEFAULT section in config.ini (as per convention in the standard library ConfigParser) UPPERCASE
Sections in config.ini files lowercase
Options in config.ini files lowercase
Directly assigned arguments lowercase

Case Sensitivity Handling

By default, ConfigParserOverride tries to stores everything as lowercase, with the exception of Section headers that are read from configuration files, where the existing casing in the file is honored. However, if you want to override such a section with an environment variable or direct assignment, it will recognize the existing casing of the section and continue to use that even though you use other casing in the override method.

It is highly discouraged, but you can make ConfigParserOverride case-sensitive by initializing it with the argument case_sensitive_overrides=True.

from configparser_override import ConfigParserOverride

parser = ConfigParserOverride(env_prefix="MYAPP_", case_sensitive_overrides=True)

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

configparser_override-0.5.0.tar.gz (18.9 kB view hashes)

Uploaded Source

Built Distribution

configparser_override-0.5.0-py3-none-any.whl (14.0 kB view hashes)

Uploaded Python 3

Supported by

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