confattr.configfile module

This module defines the ConfigFile class which can be used to load and save config files.

class confattr.configfile.ArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=<class 'argparse.HelpFormatter'>, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True)

Bases: ArgumentParser

error(message: string)

Prints a usage message incorporating the message to stderr and exits.

If you override this in a subclass, it should not return – it should either exit or raise an exception.

class confattr.configfile.ConfigFile(*, notification_level: Union[Config[NotificationLevel], NotificationLevel] = NotificationLevel.ERROR, appname: str, authorname: Optional[str] = None, config_instances: dict[str, confattr.config.Config[Any]] = {}, commands: Optional[Sequence[type[confattr.configfile.ConfigFileCommand]]] = None)

Bases: object

Read or write a config file.

Parameters:
  • notification_level – Messages of a lower priority are not passed to the callback registered with set_ui_callback()

  • appname – The name of the application, required for generating the path of the config file if you use load() or save()

  • authorname – The name of the developer of the application, on MS Windows useful for generating the path of the config file if you use load() or save()

  • config_instances – The Config instances to load or save, defaults to Config.instances

  • commands – The ConfigFileCommand`s allowed in this config file, if this is :const:`None: use the return value of ConfigFileCommand.get_command_types()

COMMENT = '#'
COMMENT_PREFIXES = ('"', '#')
ENTER_GROUP_PREFIX = '['
ENTER_GROUP_SUFFIX = ']'
FILENAME = 'config'

The name of the config file used by iter_config_paths(). Can be changed with the environment variable CONFATTR_FILENAME.

config_id: Optional[ConfigId]
enter_group(ln: str) bool

Check if ln starts a new group and set config_id if it does.

Parameters:

ln – The current line

Returns:

True if ln starts a new group

get_app_dirs() AppDirs

Create or get a cached AppDirs instance with multipath support enabled.

When creating a new instance, platformdirs, xdgappdirs and appdirs are tried, in that order. The first one installed is used. appdirs, the original of the two forks and the only one of the three with type stubs, is specified in pyproject.toml as a hard dependency so that at least one of the three should always be available. I am not very familiar with the differences but if a user finds that appdirs does not work for them they can choose to use an alternative with pipx inject appname xdgappdirs|platformdirs.

These libraries should respect the environment variables XDG_CONFIG_HOME and XDG_CONFIG_DIRS.

is_comment(ln: str) bool

Check if ln is a comment.

Parameters:

ln – The current line

Returns:

True if ln is a comment

iter_config_paths() Iterator[str]

Iterate over all paths which are checked for config files, user specific first.

Use this method if you want to tell the user where the application is looking for it’s config file. The first existing file yielded by this method is used by load().

The paths are generated by joining the directories yielded by iter_user_site_config_paths() with ConfigFile.FILENAME (the value of the environment variable CONFATTR_FILENAME if it is set or 'config').

iter_user_site_config_paths() Iterator[str]

Iterate over all directories which are searched for config files, user specific first.

The directories are based on get_app_dirs().

load() None

Load the first existing config file returned by iter_config_paths().

If there are several config files a user specific config file is preferred. If a user wants a system wide config file to be loaded, too, they can explicitly include it in their config file.

load_file(fn: str) None

Load a config file and change the Config objects accordingly.

Use set_ui_callback() to get error messages which appeared while loading the config file. You can call set_ui_callback() after this method without loosing any messages.

Parameters:

fn – The file name of the config file (absolute or relative path)

load_without_resetting_config_id(fn: str) None
parse_error(msg: str, **kw: Unpack[ParseSplittedLineKwargs]) None

Is called if something went wrong while trying to load a config file.

This method is called when a ParseException or MultipleParseExceptions is caught. This method compiles the given information into an error message and calls UiNotifier.show_error().

Parameters:
  • msg – The error message

  • line – The line where the error occured

  • line_number – The number of the line

  • file_name – The name of the config file from which the line has been read

parse_line(line: str, **kw: Unpack[ParseLineKwargs]) None
Parameters:
  • line – The line to be parsed

  • line_number – The number of the line, used in error messages

  • file_name – The name of the file from which ln was read (absolute or relative path), used in error messages and for relative imports

line_number and file_name don’t need to be passed in case ln is not read from a config file but from a command line.

parse_error() is called if something goes wrong, e.g. invalid key or invalid value.

parse_splitted_line(ln_splitted: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None
quote(val: str) str

Quote a value if necessary so that it will be interpreted as one argument.

The default implementation calls readable_quote().

save(**kw: Unpack[SaveKwargs]) str

Save the current values of all settings to the first existing and writable file returned by iter_config_paths() or to the first path if none of the files are existing and writable.

In case no writable file is found the directories are created as necessary.

Parameters:
  • config_instances – Do not save all settings but only those given. If this is a list they are written in the given order. If this is a set they are sorted by their keys.

  • ignore – Do not write these settings to the file.

  • no_multi – Do not write several sections. For MultiConfig instances write the default values only.

  • comments – Write comments with allowed values and help.

Returns:

The path to the file which has been written

save_file(fn: str, **kw: Unpack[SaveKwargs]) None

Save the current values of all settings to a specific file.

Parameters:

fn – The name of the file to write to. If this is not an absolute path it is relative to the current working directory.

Raises:

FileNotFoundError – if the directory does not exist

For an explanation of the other parameters see save().

save_to_open_file(f: TextIO, **kw: Unpack[SaveKwargs]) None

Save the current values of all settings to file-like object.

Parameters:

f – The file to write to

For an explanation of the other parameters see save().

set_ui_callback(callback: Callable[[NotificationLevel, str | BaseException], None]) None

Register a callback to a user interface in order to show messages to the user like syntax errors or invalid values in the config file.

Messages which occur before this method is called are stored and forwarded as soon as the callback is registered.

Parameters:

ui_callback – A function to display messages to the user

write_config_id(f: TextIO, config_id: ConfigId) None

Start a new group in the config file so that all following commands refer to the given config_id.

class confattr.configfile.ConfigFileArgparseCommand(config_file: ConfigFile)

Bases: ConfigFileCommand

An abstract subclass of ConfigFileCommand which uses argparse to make parsing and providing help easier.

You must implement the class method init_parser() to add the arguments to parser. Instead of run() you must implement run_parsed(). You don’t need to add a usage or the possible arguments to the doc string as argparse will do that for you. You should, however, still give a description what this command does in the doc string.

You may specify ConfigFileCommand.name, ConfigFileCommand.aliases and ConfigFileCommand.save() like for ConfigFileCommand.

aliases: tuple[str, ...] | list[str]

Alternative names which can be used in the config file.

classmethod get_help() str
Returns:

A help text which can be presented to the user. This is generated by ArgumentParser.format_help(). The return value of ConfigFileCommand.get_help() has been passed as description to the constructor of ArgumentParser, therefore help/the doc string are included as well.

help: str

A description which may be used by an in-app help. If this is not set get_help() uses the doc string instead.

abstract classmethod init_parser() None

This is an abstract method which must be implemented by subclasses. Use ArgumentParser.add_argument() to add arguments to parser.

name: str

The name which is used in the config file to call this command. Use an empty string to define a default command which is used if an undefined command is encountered. If this is not set get_name() returns the name of this class in lower case letters and underscores replaced by hyphens.

parser: ArgumentParser
run(ln: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None

Process one line which has been read from a config file

Raises:
abstract run_parsed(args: Namespace) None

This is an abstract method which must be implemented by subclasses.

class confattr.configfile.ConfigFileCommand(config_file: ConfigFile)

Bases: ABC

An abstract base class for commands which can be used in a config file.

Subclasses must implement the run() method which is called when ConfigFile is loading a file. Subclasses should contain a doc string so that get_help() can provide a description to the user. Subclasses may set the name and aliases attributes to change the output of get_name() and get_names().

All subclasses are remembered and can be retrieved with get_command_types(). They are instantiated in the constructor of ConfigFile.

aliases: tuple[str, ...] | list[str]

Alternative names which can be used in the config file.

classmethod delete_command_type(cmd: type[confattr.configfile.ConfigFileCommand]) None

Delete cmd so that it is not returned anymore by get_command_types() and that it’s name can be used by another command. Do nothing if cmd has already been deleted.

classmethod get_command_types() tuple[type[confattr.configfile.ConfigFileCommand], ...]
Returns:

All subclasses of ConfigFileCommand which have not been deleted with delete_command_type()

classmethod get_help() str
Returns:

A help text which can be presented to the user. The default implementation returns help if given or the doc string otherwise, preprocessed by inspect.cleandoc().

classmethod get_name() str
Returns:

The name which is used in config file to call this command.

If name is set it is returned as it is. Otherwise a name is generated based on the class name.

classmethod get_names() Iterator[str]
Returns:

Several alternative names which can be used in a config file to call this command.

The first one is always the return value of get_name(). If aliases is set it’s items are yielded afterwards.

If one of the returned items is the empty string this class is the default command and run() will be called if an undefined command is encountered.

help: str

A description which may be used by an in-app help. If this is not set get_help() uses the doc string instead.

name: str

The name which is used in the config file to call this command. Use an empty string to define a default command which is used if an undefined command is encountered. If this is not set get_name() returns the name of this class in lower case letters and underscores replaced by hyphens.

abstract run(ln: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None

Process one line which has been read from a config file

Raises:
save(f: TextIO, **kw: Unpack[SaveKwargs]) None

Write as many calls to this command as necessary to the config file in order to create the current state. There is the config_file attribute (which was passed to the constructor) which you can use to: - quote arguments with ConfigFile.quote() - get the comment character ConfigFile.COMMENT - call write_config_id

The default implementation does nothing.

confattr.configfile.DEFAULT_COMMAND = ''

If the name or an alias of ConfigFileCommand is this value that command is used by ConfigFile.parse_splitted_line() if an undefined command is encountered.

class confattr.configfile.Include(config_file: ConfigFile)

Bases: ConfigFileCommand

run(cmd: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None

Process one line which has been read from a config file

Raises:
exception confattr.configfile.MultipleParseExceptions(exceptions: Sequence[ParseException])

Bases: Exception

This is raised and caught inside of ConfigFile to communicate errors while parsing a config file where multiple settings are set in the same line. If you don’t intend to subclass ConfigFile you do not need to worry about this class.

class confattr.configfile.NotificationLevel(value)

Bases: SortedEnum

An enumeration.

ERROR = 'error'
INFO = 'info'
exception confattr.configfile.ParseException

Bases: Exception

This is raised and caught inside of ConfigFile to communicate errors while parsing a config file. If you don’t intend to subclass ConfigFile you do not need to worry about this class.

class confattr.configfile.ParseLineKwargs

Bases: TypedDict

file_name: str
line_number: int
class confattr.configfile.ParseSplittedLineKwargs

Bases: dict

file_name: str
line: Required[str]
line_number: int
class confattr.configfile.SaveKwargs

Bases: TypedDict

comments: bool
config_instances: Iterable[Union[Config[Any], DictConfig[Any, Any]]]
ignore: collections.abc.Iterable[Union[confattr.config.Config[Any], confattr.config.DictConfig[Any, Any]]] | None
no_multi: bool
class confattr.configfile.Set(config_file: ConfigFile)

Bases: ConfigFileCommand

KEY_VAL_SEP = '='

The separator which is used between a key and it’s value

aliases: tuple[str, ...] | list[str]

Alternative names which can be used in the config file.

format_value(instance: Config[Any], config_id: Optional[ConfigId]) str
Parameters:
  • instance – The config value to be saved

  • config_id – Which value to be written in case of a MultiConfig, should be None for a normal Config instance

Returns:

A str representation to be written to the config file

Convert the value of the Config instance into a str with Config.format_value().

help: str

A description which may be used by an in-app help. If this is not set get_help() uses the doc string instead.

iter_config_instances_to_be_saved(**kw: Unpack[SaveKwargs]) Iterator[Config[object]]
Parameters:
  • config_instances – The settings to consider

  • ignore – Skip these settings

Iterate over all given config_instances and expand all DictConfig instances into the Config instances they consist of. Sort the resulting list if config_instances is not a list or a tuple. Yield all Config instances which are not (directly or indirectly) contained in ignore and where Config.wants_to_be_exported() returns true.

name: str

The name which is used in the config file to call this command. Use an empty string to define a default command which is used if an undefined command is encountered. If this is not set get_name() returns the name of this class in lower case letters and underscores replaced by hyphens.

parse_and_set_value(instance: Config[Any], value: str) None

Parse the given value str and assign it to the given instance by calling Config.parse_and_set_value() with ConfigFile.config_id of config_file. Afterwards call UiNotifier.show_info().

parse_key_and_set_value(key: str, value: str) None

Find the corresponding Config instance for key and pass it to parse_and_set_value().

Raises:

ParseException – if key is invalid or parse_and_set_value() raises a ValueError

primitive_types = {<class 'str'>, <class 'bool'>, <class 'int'>, <class 'float'>}

data types which have no help, these are skipped by write_data_types()

run(cmd: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None

Call set_multiple() if the first argument contains KEY_VAL_SEP otherwise set_with_spaces().

Raises:

ParseException – if something is wrong (no arguments given, invalid syntax, invalid key, invalid value)

save(f: TextIO, **kw: Unpack[SaveKwargs]) None
Parameters:
  • f – The file to write to

  • no_multi (bool) – If true: treat MultiConfig instances like normal Config instances and only write their default value. If false: Separate MultiConfig instances and print them once for every MultiConfig.config_ids.

  • comments (bool) – If false: don’t call write_data_types().

Iterate over all Config instances with iter_config_instances_to_be_saved(), split them into normal Config and MultiConfig and write them with save_config_instance(). But before that set last_name to None (which is used by write_help()) and call write_data_types().

save_config_instance(f: TextIO, instance: Config[object], config_id: ConfigId | None, **kw: Unpack[SaveKwargs]) None
Parameters:
  • f – The file to write to

  • instance – The config value to be saved

  • config_id – Which value to be written in case of a MultiConfig, should be None for a normal Config instance

  • comments (bool) – If true: call write_help()

Convert the Config instance into a value str with format_value(), wrap it in quotes if necessary with config_file.quote() and print it to f.

set_multiple(cmd: Sequence[str]) None

Process one line of the format set key=value [key2=value2 ...]

Raises:

MultipleParseExceptions – if something is wrong (invalid syntax, invalid key, invalid value)

set_with_spaces(cmd: Sequence[str]) None

Process one line of the format set key [=] value

Raises:

ParseException – if something is wrong (invalid syntax, invalid key, invalid value)

static strip_indentation(lines: Iterable[str]) Iterator[str]

Strip the indentation of the first line from all lines.

Raises:

AssertionError – if one of the following lines does not start with the same indentation

write_data_types(f: TextIO, config_instances: Iterable[Config[object]]) None
Parameters:
  • f – The file to write to

  • config_instances – All config values to be saved

Write comments which explain all non-primitive data types occurring in config_instances based on their help attribute.

write_help(f: TextIO, instance: Config[Any]) None
Parameters:
  • f – The file to write to

  • instance – The config value to be saved

Write a comment which explains the meaning and usage of this setting based on Config.format_allowed_values_or_type() and Config.help.

Use last_name to write the help only once for all Config instances belonging to the same DictConfig instance.

class confattr.configfile.SortedEnum(value)

Bases: Enum

An enumeration.

class confattr.configfile.UiNotifier(notification_level: Union[Config[NotificationLevel], NotificationLevel] = NotificationLevel.ERROR)

Bases: object

Most likely you will want to load the config file before creating the UI. But if there are errors in the config file the user will want to know about them. This class takes the messages from ConfigFile and stores them until the UI is ready. When you call set_ui_callback() the stored messages will be forwarded and cleared.

This object can also filter the messages. ConfigFile calls show_info() every time a setting is changed. If you load an entire config file this can be many messages and the user probably does not want to see them all. Therefore this object drops all messages of NotificationLevel.INFO by default. Pass notification_level to the constructor if you don’t want that.

property notification_level: NotificationLevel
set_ui_callback(callback: Callable[[NotificationLevel, str | BaseException], None]) None
show(notification_level: NotificationLevel, msg: str | BaseException, *, ignore_filter: bool = False) None
show_error(msg: str | BaseException, *, ignore_filter: bool = False) None
show_info(msg: str, *, ignore_filter: bool = False) None
class confattr.configfile.UnknownCommand(config_file: ConfigFile)

Bases: ConfigFileCommand

name: str = ''

The name which is used in the config file to call this command. Use an empty string to define a default command which is used if an undefined command is encountered. If this is not set get_name() returns the name of this class in lower case letters and underscores replaced by hyphens.

run(splitted_line: Sequence[str], **kw: Unpack[ParseSplittedLineKwargs]) None

Process one line which has been read from a config file

Raises:
confattr.configfile.readable_quote(value: str) str

This function has the same goal like shlex.quote() but tries to generate better readable output.

Parameters:

value – A value which is intended to be used as a command line argument

Returns:

A POSIX compliant quoted version of value