tranche

class tranche.Tranche

Bases: object

A “meta” config parser that keeps a dictionary of config parsers and their sources to combine when needed. The custom config parser allows provenance of the source of different config options and allows the “user” config options to always take precedence over other config options (even if they are added later).

Example

>>> config = Tranche()
>>> config.add_from_file('default.cfg')
>>> config.add_user_config('user.cfg')
>>> value = config.get('section', 'option')
combined

The combined config options

Type:

{None, configparser.ConfigParser}

combined_comments

The combined comments associated with sections and options

Type:

{None, dict}

sources

The source of each section or option

Type:

{None, dict}

add_from_file(filename)

Add the contents of a config file to the parser.

Parameters:

filename (str) – The relative or absolute path to the config file

Return type:

None

add_from_package(package, config_filename, exception=True)

Add the contents of a config file to the parser.

Parameters:
  • package (str or Package) – The package where config_filename is found

  • config_filename (str) – The name of the config file to add

  • exception (bool, optional) – Whether to raise an exception if the config file isn’t found

Return type:

None

add_section(section, user=False)

Add an empty section. The file from which this function was called is retained for provenance, mirroring set().

Parameters:
  • section (str) – The name of the config section to add

  • user (bool, optional) – Whether this section was supplied by the user and should take priority over other sources

Raises:

configparser.DuplicateSectionError – If the section already exists in the calling file’s layer

Return type:

None

add_user_config(filename)

Add a the contents of a user config file to the parser. These options take precedence over all other options.

Parameters:

filename (str) – The relative or absolute path to the config file

Return type:

None

append(other)

Append a deep copy of another config parser to this one. Config options from other will take precedence over those from this config parser.

Parameters:

other (tranche.Tranche) – The other, higher priority config parser

Return type:

None

combine(raw=False)

Combine the config files into one. This is normally handled automatically.

Parameters:

raw (bool, optional) – Whether to combine “raw” config options, rather than using extended interpolation

Return type:

None

copy()

Get a deep copy of the config parser

Returns:

config_copy – The deep copy

Return type:

tranche.Tranche

defaults()

Get the options in the special [DEFAULT] section.

Returns:

defaults – The fallback options applied to every section

Return type:

Mapping[str, str]

explain(section, option)

Explain the provenance of an option.

Returns a dictionary with the effective value, the source file path, and which layer provided it (“user” or “base”).

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

Returns:

info – {“value”: …, “source”: <path>, “layer”: “user”|”base”}

Return type:

dict

get(section, option, **kwargs)

Get an option value for a given section.

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

  • **kwargs (Any) – Additional keyword arguments forwarded to configparser.ConfigParser.get().

Returns:

value – The value of the config option

Return type:

str | None

getboolean(section, option, **kwargs)

Get an option boolean value for a given section.

Parameters:
Returns:

value – The value of the config option

Return type:

bool | None

getexpression(section, option, dtype=None, backend=None, allow_numpy=False, fallback=None, **kwargs)

Get an option as an expression (typically a list, though tuples and dicts are also available). The expression is required to have valid python syntax, so that string entries are required to be in single or double quotes.

Parameters:
  • section (str) – The section in the config file

  • option (str) – The option in the config file

  • dtype ({Type[bool], Type[int], Type[float], Type[list], Type[tuple], Type[str]}, optional) – If supplied, each element in a list or tuple, or each value in a dictionary are cast to this type. This is likely most useful for ensuring that all elements in a list of numbers are of type float, rather than int, when the distinction is important.

  • backend ({"literal", "safe"} or None) –

    • None (default): choose “safe” if allow_numpy=True else “literal”.

    • ”literal”: use ast.literal_eval (safest, literals only)

    • ”safe”: use a whitelisted AST evaluator optionally allowing numpy

  • allow_numpy (bool, optional) – If True and backend=”safe”, enable limited numpy functions (np.arange, np.linspace, np.array) under names “np”/”numpy”.

  • fallback (Any, optional) – A fallback value to return if the option is not found.

  • **kwargs (Any) – Additional keyword arguments forwarded to configparser.ConfigParser.get().

Return type:

Any

getfloat(section, option, **kwargs)

Get an option float value for a given section.

Parameters:
Returns:

value – The value of the config option

Return type:

float | None

getint(section, option, **kwargs)

Get an option integer value for a given section.

Parameters:
Returns:

value – The value of the config option

Return type:

int | None

getlist(section, option, dtype=<class 'str'>, *, fallback=None, **kwargs)

Get an option value as a list for a given section.

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

  • dtype ({Type[str], Type[int], Type[float]}) – The type of the elements in the list.

  • fallback (list, optional) – A fallback value to return if the option is not found.

  • **kwargs (Any) – Additional keyword arguments forwarded to configparser.ConfigParser.get().

Returns:

value – The value of the config option parsed into a list.

Return type:

list | None

getnumpy(section, option, dtype=None, backend=None, fallback=None, **kwargs)

Shortcut for expressions requiring NumPy.

Equivalent to getexpression(..., allow_numpy=True) with adaptive backend selection (safe if backend is None).

Parameters:
  • section (str) – Section name.

  • option (str) – Option name.

  • dtype (type, optional) – Cast list/tuple/dict elements to this type.

  • backend ({"literal", "safe"} or None, optional) – Override backend. None => choose “safe”.

  • fallback (Any, optional) – A fallback value to return if the option is not found.

  • **kwargs (Any) – Additional keyword arguments forwarded to configparser.ConfigParser.get().

Return type:

Any

has_option(section, option)

Whether the given section has the given option

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

Returns:

found – Whether the option was found in the section

Return type:

bool

has_section(section)

Whether the given section is part of the config

Parameters:

section (str) – The name of the config section

Returns:

found – Whether the option was found in the section

Return type:

bool

items(section=<object object>, **kwargs)

Get section or option items from the combined config.

Mirrors configparser.ConfigParser.items().

Parameters:
  • section (str, optional) – If given, return a list of (option, value) pairs for that section. If omitted, return a list of (name, section) pairs for every section, where each section is a tranche.section.Section wrapper.

  • **kwargs (Any) – Additional keyword arguments (e.g. raw, vars) forwarded to configparser.ConfigParser.items() when section is given.

Returns:

items – Either (name, Section) pairs or (option, value) pairs.

Return type:

list

keys()

Get the section names in the combined config (including DEFAULT).

Returns:

keys – The section names, mirroring mapping access via config[section]

Return type:

list of str

list_files()

Get a list of files contributing to the combined config options

Returns:

filenames – A list of file paths

Return type:

list of str

options(section)

Get the list of option names available in the given section.

Parameters:

section (str) – The name of the config section

Returns:

options – The names of the options in the section

Return type:

list of str

prepend(other)

Prepend a deep copy of another config parser to this one. Config options from this config parser will take precedence over those from other.

Parameters:

other (tranche.Tranche) – The other, higher priority config parser

Return type:

None

read_dict(dictionary, source='<dict>', user=False)

Add config options read from a nested dictionary.

This mirrors configparser.ConfigParser.read_dict(). Keys and values are converted to strings. Options added this way have empty comments.

Parameters:
  • dictionary (Mapping[str, Mapping[str, Any]]) – A mapping of the form {section: {option: value, ...}, ...}.

  • source (str, optional) – A label used as the provenance “source” for these options. If several calls share a source, later options overwrite earlier ones.

  • user (bool, optional) – Whether these options should be treated as user overrides that take precedence over all base options.

Return type:

None

read_file(f, source=None, user=False)

Add config options read from an open file or iterable of lines.

This mirrors configparser.ConfigParser.read_file() while preserving comments, provenance and layered precedence.

Parameters:
  • f (iterable of str) – An open file object or any iterable yielding config lines.

  • source (str, optional) – A label used as the provenance “source” for these options. If not given, f.name is used when available, otherwise "<stream>". A later call with the same source replaces the earlier layer.

  • user (bool, optional) – Whether these options should be treated as user overrides that take precedence over all base options.

Return type:

None

read_string(string, source='<string>', user=False)

Add config options read from a string.

This mirrors configparser.ConfigParser.read_string() while preserving comments, provenance and layered precedence. Environment variables of the form ${env:VAR} are interpolated, just as for add_from_file().

Parameters:
  • string (str) – The config contents to parse.

  • source (str, optional) – A label used as the provenance “source” for these options. A later call with the same source replaces the earlier layer.

  • user (bool, optional) – Whether these options should be treated as user overrides that take precedence over all base options.

Return type:

None

register_symbol(name, obj)

Make ‘name’ available to the safe expression backend.

Restrictions:

  • name must not contain ‘__’ or ‘.’

  • cannot override reserved core names: ‘np’, ‘numpy’, ‘math’, ‘range’, ‘int’, ‘float’, ‘pi’

Examples

Register a stdlib function (math.sqrt) and call it from the config:

>>> import math
>>> config = Tranche()
>>> config.register_symbol('sqrt', math.sqrt)
>>> # INI has:
>>> #  [calc]
>>> #  val = sqrt(9)
>>> config.getexpression('calc', 'val', backend='safe')
3.0

Register a reducer (statistics.mean):

>>> import statistics
>>> config.register_symbol('mean', statistics.mean)
>>> # INI has:
>>> #  [data]
>>> #  avg = mean([1, 2, 3])
>>> config.getexpression('data', 'avg', backend='safe')
2

Register a type (datetime.timedelta) supporting keyword args:

>>> from datetime import timedelta
>>> config.register_symbol('timedelta', timedelta)
>>> # INI has:
>>> #  [sched]
>>> #  interval = timedelta(days=2)
>>> config.getexpression('sched', 'interval', backend='safe')
datetime.timedelta(days=2)
Parameters:
  • name (str) – The name to register

  • obj (any) – The object to register under the given name

Return type:

None

remove_option(section, option)

Remove an option from a section across all layers.

The option is removed from every contributing file (both base and user layers) so that it no longer appears in the combined config.

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

Returns:

existed – Whether the option existed in any layer before removal

Return type:

bool

Raises:

configparser.NoSectionError – If the section is not present in any layer

remove_section(section)

Remove a section and all of its options across all layers.

The section is removed from every contributing file (both base and user layers) so that it no longer appears in the combined config.

Parameters:

section (str) – The name of the config section

Returns:

existed – Whether the section existed in any layer before removal

Return type:

bool

sections()

Get the list of section names in the combined config.

The special [DEFAULT] section is not included, mirroring configparser.ConfigParser.sections().

Returns:

sections – The names of the config sections

Return type:

list of str

set(section, option, value=None, comment=None, user=False)
Set the value of the given option in the given section. The file from

which this function was called is also retained for provenance.

Parameters:
  • section (str) – The name of the config section

  • option (str) – The name of the config option

  • value (str, optional) – The value to set the option to

  • comment (str, optional) – A comment to include with the config option when it is written to a file

  • user (bool, optional) – Whether this config option was supplied by the user (e.g. through a command-line flag) and should take priority over other sources

Return type:

None

validate(validator)

Call a user-provided validator function on the config as a nested dict.

The validator is called with a dictionary of the form:

{section: {option: value, …}, …}

where all values are strings as returned by get().

This allows integration with validation libraries such as Pydantic or voluptuous, or custom validation logic. If the validator raises an exception, it will propagate to the caller.

Parameters:

validator (Callable[[dict[str, dict[str, str]]], None]) – A function that takes a nested dictionary of config values and raises on error.

Return type:

None

Examples

>>> def my_validator(cfg):
...     assert 'main' in cfg
...     assert 'foo' in cfg['main']
>>> config.validate(my_validator)
values()

Get a tranche.section.Section wrapper for each section.

Returns:

values – The sections of the combined config

Return type:

list of tranche.section.Section

write(fp, include_sources=True, include_comments=True, raw=True)

Write the config options to the given file pointer.

Parameters:
  • fp (TextIO) – The file pointer to write to.

  • include_sources (bool, optional) – Whether to include a comment above each option indicating the source file where it was defined

  • include_comments (bool, optional) – Whether to include the original comments associated with each section or option

  • raw (bool, optional) – Whether to write “raw” config options, rather than using extended interpolation

Return type:

None