ddp_utils.config¶
import ddp_utils.config
Best-effort configuration parsing, INI loading, environment overrides and watching.
Parsing is heuristic, not schema validation. Check the documented edge cases before accepting untrusted input or depending on exact preservation of strings.
Examples
Use this public operation:
import ddp_utils.config
- ddp_utils.config.smart_parse(value: str) Any¶
Convert a stripped configuration string using ordered heuristics.
Case-insensitive true/false and null/none are recognized before numbers. Current boolean checks use substring membership: nonempty substrings of ‘true’ become True, then substrings of ‘false’ become False. This is not strict boolean parsing; use to_bool for explicit accepted tokens.
Integer/decimal/exponent forms become numbers. Braced/bracketed values use parse_json_like; comma-and-colon text is tried as a dictionary; remaining comma text becomes a list with empty parts omitted. Finally matching outer quotes are removed, or the stripped text is returned. Bare yes/no/on/off stay strings; 1/0 are integers. Quote removal happens after comma splitting.
Parameters
Name
Type
Description
value
str
Input string; whitespace-only input returns ‘’.
Returns
Type
Description
Any
Parsed scalar/list/dict or string. This does not evaluate Python code.
Examples
Use this public operation:
result = ddp_utils.config.smart_parse(value=value_value)
- ddp_utils.config.parse_json_like(s: str) dict | list | str¶
Parse JSON-like text after heuristic textual normalization.
Replaces all single quotes with double quotes, quotes bare word keys, and replaces True/False/None tokens. These substitutions are not quote-aware and can alter quoted contents. Successful JSON is passed to normalize_parsed; JSONDecodeError falls back to parse_custom_structure on the original input.
Parameters
Name
Type
Description
s
str
JSON-like input string, including braced mappings and bracketed lists.
Returns
Type
Description
dict | list | str
Parsed and normalized object, or a best-effort structure/string fallback. Scalar JSON can also return a scalar despite the narrower annotation.
Examples
Use this public operation:
result = ddp_utils.config.parse_json_like(s=s_value)
- ddp_utils.config.parse_custom_structure(s: str) dict | list | str¶
Parse braced dictionaries or bracketed lists without requiring valid JSON.
Parameters
Name
Type
Description
s
str
String stripped before parsing. Top-level commas are split with split_preserve_brackets. Dict entries without a colon are skipped; keys lose matching quotes; values pass through smart_parse.
Returns
Type
Description
dict | list | str
Dict/list for recognized delimiters,
{}or[]for empty structures, otherwise the stripped original string. Duplicate dict keys use the last value.Examples
Use this public operation:
result = ddp_utils.config.parse_custom_structure(s=s_value)
- ddp_utils.config.split_preserve_brackets(text: str, delimiter: str = ',') list¶
Split on a character outside quotes and nested brackets, stripping parts.
Parameters
Name
Type
Description
text
str
Input string. Bracket balance is tracked but not validated.
delimiter
str
One-character separator; multi-character values never match. Quoted text and (), [] and {} protect enclosed separators.
Returns
Type
Description
list
List of stripped pieces. Consecutive/leading delimiters produce empty pieces; a final delimiter produces no extra trailing piece. Empty text returns []. Escaped quotes use a simple preceding-backslash check.
Examples
Use this public operation:
result = ddp_utils.config.split_preserve_brackets(text=text_value)
- ddp_utils.config.normalize_parsed(obj: Any) Any¶
Recursively normalize dict values, list items and scalar strings.
Parameters
Name
Type
Description
obj
Any
Parsed object. Dict keys and non-string scalars are unchanged. Matching outer quotes are removed from strings; case-insensitive true/false/null become booleans/None, then float (with a dot) or int conversion is attempted. ‘none’ is not treated as null here.
Returns
Type
Description
Any
New dict/list containers with converted values, or the normalized scalar. Exponent-only strings such as ‘1e2’ remain strings without a decimal point.
Examples
Use this public operation:
result = ddp_utils.config.normalize_parsed(obj=obj_value)
- ddp_utils.config.cnf_get_all(ini: str | bytes | PathLike, path_to_merge: str | bytes | PathLike | None = None) Dict[str, Any]¶
Read an INI file without interpolation and parse values with smart_parse.
Section and option names are stripped, lowercased and have spaces replaced with underscores. DEFAULT values are also inherited by ordinary sections according to ConfigParser behavior. Missing files yield {‘default’: {}}.
Parameters
Name
Type
Description
ini
str | bytes | PathLike
Filename accepted by ConfigParser.read; decoding follows its default.
path_to_merge
str | bytes | PathLike | None
Compatibility argument, currently ignored.
Returns
Type
Description
Dict[str, Any]
Mapping of normalized section names to parsed option dictionaries, always including ‘default’. INI parsing errors propagate.
Examples
Use this public operation:
result = ddp_utils.config.cnf_get_all(ini=ini_value)
- ddp_utils.config.to_bool(value: Any, default: T = False) bool | T¶
Safely convert config values to bool.
Supports:
bool
int / float
strings: true/false/1/0/yes/no/on/off
The default value is intentionally generic. This allows strict callers to pass
default=Noneand detect invalid values instead of silently falling back to False.Parameters
Name
Type
Description
value
Any
raw config value.
default
T
fallback if value is None or unrecognized.
Returns
Type
Description
bool | T
bool if conversion succeeds, otherwise default.
Examples
Use this public operation:
result = ddp_utils.config.to_bool(value=value_value)
- ddp_utils.config.to_int(value: Any, default: int = 0) int¶
Coerce runtime value to int with safe fallback.
Parameters
Name
Type
Description
value
Any
raw value.
default
int
fallback if conversion fails.
Returns
Type
Description
int
int
Examples
Use this public operation:
result = ddp_utils.config.to_int(value=value_value)
- ddp_utils.config.to_float(value: Any, default: float = 0.0) float¶
Coerce runtime value to float with safe fallback.
Parameters
Name
Type
Description
value
Any
raw value.
default
float
fallback if conversion fails.
Returns
Type
Description
float
float
Examples
Use this public operation:
result = ddp_utils.config.to_float(value=value_value)
- ddp_utils.config.path_list_to_str(obj: Any, key: str) Any¶
Recursively mutate matching values in dict/list containers via os.path.join.
Despite the function name, the implementation passes the value as ONE argument rather than unpacking a list of path components. A list-valued matching key therefore raises TypeError; a string/path-like value works.
Parameters
Name
Type
Description
obj
Any
Dict/list to mutate; other objects pass through unchanged.
key
str
Exact dictionary key whose value is passed to os.path.join.
Returns
Type
Description
Any
Same input object after recursive mutation; earlier changes remain on failure.
Examples
Use this public operation:
result = ddp_utils.config.path_list_to_str(obj=obj_value, key=key_value)
- ddp_utils.config.load_project_manifest(manifest_dir: str | bytes | PathLike, filename: str = 'manifest.cfg') Dict[str, Any] | None¶
Load an INI manifest and separate defaults from named sections.
Returns None when the target is missing or not a regular file. Otherwise cnf_get_all supplies the data for this structure:
{ "default": {...}, "sections": { "section1": {...}, "section2": {...} }, "options": {...}, # default keys plus nested section dictionaries "path": "<absolute manifest path>" }
Parameters
Name
Type
Description
manifest_dir
str | bytes | PathLike
Directory containing the manifest.
filename
str
Manifest name, default ‘manifest.cfg’.
Returns
Type
Description
Dict[str, Any] | None
Dict with default, sections, options and path keys, or None. Section names override colliding default keys in options; options does not flatten the fields of named sections. Read/parse errors propagate.
Examples
Use this public operation:
result = ddp_utils.config.load_project_manifest(manifest_dir=manifest_dir_value)
- ddp_utils.config.cnf_apply_env(cfg: Dict[str, Any], prefix: str = '', separator: str = '__') Dict[str, Any]¶
Apply environment variables over cfg, mutating it in place.
Names are matched case-insensitively against prefix plus separator. Remaining names are lowercased and split ONCE: SECTION__KEY or a top-level KEY. Any additional separators remain in the field name. Values use smart_parse.
Parameters
Name
Type
Description
cfg
Dict[str, Any]
Destination dict; a nested target section must already be a dict or absent.
prefix
str
Application prefix; an empty string applies ALL environment variables.
separator
str
Nonempty separator string, default ‘__’.
Returns
Type
Description
Dict[str, Any]
Same cfg object. Invalid separator or incompatible section values can raise; updates already applied are not rolled back.
Examples
Apply a prefixed environment variable to an existing configuration:
import os from unittest.mock import patch from ddp_utils.config import cnf_apply_env config = {"database": {"host": "localhost"}} with patch.dict(os.environ, {"APP__DATABASE__HOST": "db.example.com"}): result = cnf_apply_env(config, prefix="APP") assert result is config assert config["database"]["host"] == "db.example.com"
- class ddp_utils.config.WatchedConfig(ini_path: str | PathLike, prefix: str = '', on_reload: Any | None = None)¶
Bases:
objectLoad INI configuration and optionally watch file-modified events with watchdog.
Without the separately installed watchdog dependency, the initial data is retained without live watching. The implementation handles modification events for the exact path, not every possible atomic-replace/save pattern.
Examples
Load a configuration and always stop its optional watcher:
from pathlib import Path from tempfile import TemporaryDirectory from ddp_utils.config import WatchedConfig with TemporaryDirectory() as directory: path = Path(directory, "config.ini") path.write_text("[database]\nhost = localhost\n", encoding="utf-8") config = WatchedConfig(path) try: assert config.get("database", "host") == "localhost" finally: config.stop()
Load the INI file immediately, invoke the callback and attempt watching.
Parameters
Name
Type
Description
ini_path
str | PathLike
INI filename, resolved to an absolute path.
prefix
str
Nonempty prefix applies cnf_apply_env after each read. An empty prefix skips environment overrides entirely here.
on_reload
Any | None
Optional callback fn(data), invoked after the initial load and each successful reload. Ordinary callback exceptions are swallowed. The callback receives the live dictionary.
Note
Missing watchdog silently disables watching. Other startup errors may propagate. Construction immediately loads the file and attempts to start watching; it is not a lazy configuration descriptor.
- stop() None¶
Request watcher stop and forget it; retain the last loaded data.
Returns
Type
Description
None
None. Repeated calls are harmless; this method does not join the watcher thread.
Examples
Use this public operation:
result = instance.stop()
- get(*keys: str, default: Any = None) Any¶
Traverse keys in the current configuration snapshot.
Parameters
Name
Type
Description
*keys
str
Exact dictionary keys, e.g. (‘database’, ‘host’). No keys returns the live data dictionary, not a copy.
default
Any
Used when lookup fails or a non-dict blocks traversal. A dict default may itself be traversed by subsequent keys.
Returns
Type
Description
Any
Referenced value or default; nested mutable values are not copied.
Examples
Read nested and missing values from a watched configuration:
host = config.get("database", "host", default="localhost") debug = config.get("debug", default=False)
- all() Dict[str, Any]¶
Return a shallow top-level copy; nested dictionaries remain shared.
Returns
Type
Description
Dict[str, Any]
A new top-level dictionary containing the current configuration. Mutating a nested mutable value also affects the stored snapshot.
Examples
Obtain a top-level copy without exposing the original mapping:
snapshot = config.all() snapshot["debug"] = True
- ddp_utils.config.cnf_merge(*sources: str | PathLike | Dict[str, Any], prefix: str = '') Dict[str, Any]¶
Merge configuration sources in order, then apply prefixed environment values.
Later sources override earlier ones; nested dictionaries are merged recursively.
Parameters
Name
Type
Description
*sources
str | PathLike | Dict[str, Any]
INI paths or dictionaries.
prefix
str
Nonempty prefix enables cnf_apply_env; empty skips it.
Returns
Type
Description
Dict[str, Any]
New top-level dictionary. Newly assigned nested values are shared with source dictionaries; later recursive merges can therefore mutate those shared nested dictionaries. This is not a deep-copy merge.
Examples
Merge dictionaries from left to right:
from ddp_utils.config import cnf_merge result = cnf_merge( {"database": {"host": "localhost", "port": 5432}}, {"database": {"host": "db.example.com"}}, ) assert result["database"] == { "host": "db.example.com", "port": 5432, }