confattr.configfile module — confattr v0.5.1 documentation

# 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:

      - ParseException – if there is an error in the line (e.g. invalid syntax)

      - MultipleParseExceptions – if there are several errors in the same line

  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:

      - ParseException – if there is an error in the line (e.g. invalid syntax)

      - MultipleParseExceptions – if there are several errors in the same line

  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:

      - ParseException – if there is an error in the line (e.g. invalid syntax)

      - MultipleParseExceptions – if there are several errors in the same line

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:

      - ParseException – if there is an error in the line (e.g. invalid syntax)

      - MultipleParseExceptions – if there are several errors in the same line

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`