(concepts:configurations)

Configurations

Here we mention a few details that were not part of the Overview of the process.

Help strings

Descriptions are provided in two places: for the script itself, and for each parameter. Note that the parameter help strings are not parsed when the class is not constructed from a .py file, which is the case here (as this uses a Jupyter notebook). So we show the syntax below but do not demonstrate its use.

Note that providing a docstring for the class is always recommended, as it seems dataclasses.dataclass() fills one up if missing.

from configpile import *
from typing import ClassVar
from typing_extensions import Annotated # or `from typing import Annotated` if Python >= 3.9
from dataclasses import dataclass

@dataclass(frozen=True)
class TestConfig(Config):
    """
    Docstring describing the program 
    """

    #: Sphinx autodoc-style comment (starting with #:) describing the parameter immediately below.
    x: Annotated[int, Param.store(parsers.int_parser)]

Members of a Config subclass

There are different kinds of members in a configuration:

Parameters

They correspond to annotated field declarations, with the general syntax:

   PARAM_NAME: Annotated[PARAM_TYPE, Param.PARAM_STATIC_METHOD(PARSER, EXTRA_OPTIONS)]

where

  • PARAM_NAME is the parameter name, cannot end with an underscore _,

  • PARAM_TYPE is the Python type of the parameter,

  • PARSER is a parser instance (see Parsers),

  • EXTRA_OPTIONS modify how configpile handles the processing.

See {ref}concepts:params` for further details.

Arguments

Argument declarations provide information to configpile about how to handle command line flags that do not correspond to parameters.

For example, an configpile.arg.Expander provides a key/value pair. They often go along with a proper parameter.

Because the arguments are not fields that will be part of the dataclass (they do not store values themselves, but modify the processing), they need to be declared as class attributes using typing.ClassVar. Here is a short example.

@dataclass(frozen=True)
class ConfigWithBool(Config):

    smoothing: Annotated[bool, Param.store(parsers.bool_parser)]

    perform_smoothing: ClassVar[Expander] = Expander.make("--smoothing", "true")
    skip_smoothing: ClassVar[Expander] = Expander.make("--smoothing", "false")
ConfigWithBool.from_command_line_(args=["--perform-smoothing"])
ConfigWithBool(smoothing=True)
ConfigWithBool.from_command_line_(args=["--skip-smoothing"])
ConfigWithBool(smoothing=False)

INI handling

Sections in an INI file are parsed according to two modes:

  • the relaxed mode ignore keys that do not match known parameters,

  • the strict mode reports an error when a key is present that does not match a parameter.

Only the section names that are specified in the Config instance through the By default, configpile parses the section named common, COMMON or Common in the relaxed mode.

Example

We present an example where the two behaviors are shown.

@dataclass(frozen=True)
class ConfigWithCustomINI(Config):
    ini_relaxed_sections_ = ['all']
    ini_strict_sections_ = ['specific']

    number: Annotated[int, Param.store(parsers.int_parser)]
    word: Annotated[str, Param.store(parsers.stripped_str_parser)]
ConfigWithCustomINI.parse_ini_contents_("""
[all]
number = 123
extra_stuff = will_be_ignored

[specific]
word = hello
""")
ConfigWithCustomINI(number=123, word='hello')
ConfigWithCustomINI.parse_ini_contents_("""
[all]
number = 123

[specific]
word = hello
extra_stuff = not_ignored

""")
Err1(msg='Unknown key extra_stuff', contexts=[('ini_section', 'specific')])

Descriptions of the program

Class attributes such as prog_, description_, methods such as version_() provide information about your program that is mostly used for documentation/help purposes.

Note that those attributes are typed using :data:typing.ClassVar, and thus they are not part of the dataclass fields; see the dataclass help.

Ending names with underscores

Note that the methods, fields and attributes designed for configpile use have an underscore _ suffix. This is to avoid clashing with user-provided configuration fields that may use the same name.

In your own Config subclasses, we suggest you follow the same naming scheme: underscore suffix for any class member which is not a configuration dataclass field.