Skip to main content

gConfigs

Configuration helper for Python applications.

gConfigs provides a unified API to read configuration values from different sources:

  • Environment variables
  • Dotenv files
  • INI files
  • TOML files
  • Local mounted files in a directory
  • Individual local files

Why another config library?

I made it for myself. That's it.

Installation

Python 3.11+

pip install gconfigs

or with uv:

uv add gconfigs

Or even better. It's small enough, avoid the dependency entirely, and copy gconfigs/ into your project.

Extra effort to convince you to avoid dependencies: maybe all you need is just os.environ.

Quick Start

import gconfigs

# 1) Environment variables
envs = gconfigs.envs()
debug = envs("DEBUG", default=False, cast=bool)
home = envs("HOME", default="/")

# 2) Mounted directory (for configs or secrets)
configs = gconfigs.local_files("/run/configs")
language_code = configs("LANGUAGE_CODE", default="en-us")

# 3) Single local file
secrets = gconfigs.local_file()
db_password = secrets("/run/secrets/DB_PASSWORD")

# 4) Dotenv file
dotenvs = gconfigs.dotenvs(".env")
project_name = dotenvs("PROJECT_NAME", default="my-app")

# 5) INI file
ini = gconfigs.ini_file("./config/settings.ini")
app_name = ini("app.name", default="my-app")

# 6) TOML file
toml = gconfigs.toml_file("./config/settings.toml")
db_port = toml("database.port", cast=int)

API Overview

The package exposes six factory functions:

  • gconfigs.envs() -> reads from process environment variables
  • gconfigs.dotenvs(filepath=".env") -> reads from dotenv files
  • gconfigs.ini_file(filepath=".ini") -> reads from INI files using section.option keys
  • gconfigs.toml_file(filepath=".toml") -> reads from TOML files using dotted keys
  • gconfigs.local_files(path="/run/configs", pattern="*") -> reads from files in a directory
  • gconfigs.local_file() -> reads from a single file path provided at call time

Each factory returns a GConfigs instance.

Main call signature:

GConfigs.get(key, *, default=NOTSET, use_instead=NOTSET, strip=None, cast=None, list_sep=None, bool_values=None, **backend_kwargs)

Usage

Environment Variables

import gconfigs

envs = gconfigs.envs()

home = envs("HOME")
workers = envs("WORKERS", default="2", cast=int)
debug = envs("DEBUG", default=False, cast=bool)

Dotenv Files

import gconfigs

dotenvs = gconfigs.dotenvs("./config/.env")
dsn = dotenvs("DATABASE_DSN")

# load another dotenv file with a different GConfigs instance
other = gconfigs.dotenvs("./config/another.env")

INI Files

import gconfigs

ini = gconfigs.ini_file("./config/settings.ini")

app_name = ini("app.name")
db_host = ini("database.host")
db_port = ini("database.port", cast=int)

INI parser behavior:

  • Keys use section.option format
  • Section and option names may contain dots (e.g. [app.db] -> app.db.host)
  • Values are read as strings by default
  • Values are read literally, without interpolation (% and %(name)s are kept as is)
  • Use cast to convert values
  • Missing section/option raises KeyError

TOML Files

import gconfigs

toml = gconfigs.toml_file("./config/settings.toml")

app_name = toml("name")
db_host = toml("database.host")
db_port = toml("database.port", cast=int)
pool_size = toml("database.pool.size", cast=int)

TOML parser behavior:

  • Keys use dotted access for nested tables
  • Quoted keys containing dots also work ([servers."alpha.example.com"] -> servers.alpha.example.com.ip)
  • Values preserve native TOML types (e.g. int, bool, list)
  • Missing nested keys raise KeyError

Dotenv parser behavior:

  • Ignores lines starting with #, ;, and [section]
  • Ignores lines without =
  • Splits at the first = so values can contain =
  • Strips key whitespace
  • Accepts an optional export prefix before the key (export KEY=value)
  • Preserves value whitespace (except trailing newline characters)
  • Removes one pair of matching quotes when the value starts and ends with the same quote character (KEY="value" or KEY='value' -> value)
  • No escape sequences or inline comments (# is part of the value)
  • Last duplicated key wins

Local Mounted Files (Directory)

import gconfigs

configs = gconfigs.local_files("/run/configs")
secrets = gconfigs.local_files("/run/secrets")

api_url = configs("API_URL")
api_key = secrets("API_KEY")

How it works:

  • Relative file path is the config key
  • File content is the config value
  • Optional pattern argument filters which files are considered
  • Keys are file names directly inside the configured base path
  • Reads are restricted to the configured base path (path traversal like ../secret is blocked)
  • Recursive access is intentionally not supported (nested paths like nested/key.txt are rejected)
only_app = gconfigs.local_files("/run/configs", pattern="APP_*")

* Uses fnmatch for pattern matching. fnmatch docs

Single Local File

import gconfigs

secrets = gconfigs.local_file()
token = secrets("/run/secrets/SERVICE_TOKEN")

Common Patterns

Default Value

port = envs("PORT", default="8000")

Defaults go through strip and cast like any other value, so envs("PORT", default="8000", cast=int) returns 8000. The exception is default=None, which is returned as is, so optional settings work with any cast:

sentry_dsn = envs("SENTRY_DSN", default=None)
timeout = envs("TIMEOUT", default=None, cast=int)  # None when TIMEOUT isn't set

Fallback Key with use_instead

host = envs("SERVICE_HOST", use_instead="HOST", default="127.0.0.1")

Strip Control

By default, returned string values are stripped.

Stripping happens before casting, so values with surrounding whitespace or a trailing newline (common in mounted secret files) can still be cast. With strip=False the raw value is passed to the cast as is.

value = envs("MY_KEY")  # strip=True by default
raw_value = envs("MY_KEY", strip=False)
debug = secrets("DEBUG", cast=bool)  # file content "true\n" -> True

Type Casting

Use cast in GConfigs.get (or by calling the instance directly) to convert values.

Boolean

  • Accepts native bool values
  • Accepts case-insensitive string pairs from bool_values
  • Default bool_values pairs:
    • ("true", "false")
    • ("1", "0")
    • ("yes", "no")
    • ("y", "n")
    • ("on", "off")
debug = envs("DEBUG", default=False, cast=bool)
feature_enabled = envs(
    "FEATURE_X",
    cast=bool,
    bool_values=(("enabled", "disabled"),),
)

list, tuple, and set

  • Accepts native iterable values for conversion between list/tuple/set
  • Accepts JSON-style list strings like "[1, 2, 3]"
  • Accepts separator-delimited strings using list_sep
  • A string without the separator becomes a single-item collection (e.g. "domain.com" -> ["domain.com"])
  • An empty or whitespace-only string becomes an empty collection
  • Strings starting with "[" must be valid JSON, otherwise a ValueError is raised
hosts = envs("ALLOWED_HOSTS", cast=list)
hosts_csv = envs("ALLOWED_HOSTS_CSV", cast=list, list_sep=",")
hosts_pipe = envs("ALLOWED_HOSTS_PIPE", cast=list, list_sep="|")

coords = envs("COORDS", cast=tuple)
labels = envs("LABELS", cast=set)

dict

  • Accepts native dict values
  • Accepts JSON-style object strings like "{"workers": 2}"
options = envs("APP_OPTIONS", cast=dict)

Custom cast function or type

from decimal import Decimal

price = envs("PRICE", cast=Decimal)


def normalize_slug(value):
    return str(value).strip().lower().replace(" ", "-")


slug = envs("PROJECT_NAME", cast=normalize_slug)

Output Formatting with ValueOutput

GConfigs delegates output conversion and strip behavior to ValueOutput.

Default behavior:

  • strip=True
  • list_sep=","
  • bool_values as described in the casting section

You can pass a custom ValueOutput instance to GConfigs:

from gconfigs.gconfigs import GConfigs, ValueOutput


class DictBackend:
    def __init__(self):
        self.data = {"DEBUG": "enabled", "HOSTS": "a|b|c"}

    def keys(self):
        return self.data.keys()

    def get(self, key, **backend_kwargs):
        if key not in self.data:
            raise KeyError(f"{key} not set")
        return self.data[key]


output_fmt = ValueOutput(list_sep="|", bool_values=(("enabled", "disabled"),))
configs = GConfigs(backend=DictBackend, output_fmt=output_fmt)

debug = configs("DEBUG", cast=bool)
hosts = configs("HOSTS", cast=list)

Iteration and Utilities

GConfigs implements container and iterator protocols.

import gconfigs

envs = gconfigs.envs()

if "HOME" in envs:
    print("HOME exists")

print(len(envs))

for item in envs:
    print(item.key, item.value)

print(envs.json())

Notes:

  • Iteration yields namedtuples with key and value fields
  • Use .iterator() when you need a fresh independent iterator

Error Behavior

Typical exceptions you may see:

  • KeyError for missing environment variable or missing dotenv key
  • FileNotFoundError for missing paths/files in file backends
  • PermissionError for unreadable files in local_file backend
  • ValueError for invalid cast values

Use default=... to avoid exceptions for missing keys when appropriate.

Custom Backend

You can plug your own backend into GConfigs.

Required backend methods:

  • get(key: str, **backend_kwargs)
  • keys()

Example:

from gconfigs.gconfigs import GConfigs


class DictBackend:
    def __init__(self):
        self.data = {"NAME": "my-app", "DEBUG": "false"}

    def additional_method(self):
        return "This is an additional method in the backend class."

    def keys(self):
        return self.data.keys()

    def get(self, key, **backend_kwargs):
        if key not in self.data:
            raise KeyError(f"{key} not set")
        return self.data[key]


configs = GConfigs(backend=DictBackend)
name = configs("NAME")
debug = configs("DEBUG", cast=bool)

# You can access the backend instance directly from GConfigs instance
assert configs.backend.additional_method

License

MIT. See LICENSE-MIT.

Metadata

Release files for gconfigs 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gconfigs 2.1.0
File Size Uploaded Provenance Actions
gconfigs-2.1.0.tar.gz 11.5 kB With provenance Details for gconfigs-2.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for gconfigs 2.1.0
File Interpreter ABI Platform Actions
gconfigs-2.1.0-py3-none-any.whl Python 3 none any Details for gconfigs-2.1.0-py3-none-any.whl

Total release size: 24.5 kB

Release files / gconfigs-2.1.0.tar.gz

Download URL gconfigs-2.1.0.tar.gz
Size 11.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5e642e144dd24ebdc7a2cd889ebae40e676ef0bf491d7f89076dd38ff36c60d4
BLAKE2b-256 checksum
How to use checksums
f12b02834ea1a00f93feb6f08354c04e5e543a4be88051a0611c02ac5fdca45e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / gconfigs-2.1.0-py3-none-any.whl

Download URL gconfigs-2.1.0-py3-none-any.whl
Size 13.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c6e945a46939b54fc50b6ad8bbf1edf4722629ef881e7f5cf306fb2c3445d4aa
BLAKE2b-256 checksum
How to use checksums
a7bee4d1e4459307220d82ebc6e7080eabab677657f31070b7047c1ae23ffbfd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Security for gconfigs 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gconfigs-2.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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