# Config

Store configuration in `ConfigNamespace` objects and provide tools for reloading, and displaying help messages.

## Configuration Reloading

Configuration reloading is supported using a `ConfigFacade`, which composes a `ConfigurationWatcher` and a `ReloadCallbackChain`. These classes provide a way of reloading configuration when the file is modified.

class staticconf.config.ConfigFacade(watcher: ConfigurationWatcher)

  A facade around a `ConfigurationWatcher` and a `ReloadCallbackChain`. See `ConfigFacade.load()`.

  When a `ConfigFacade` is loaded it will clear the namespace of all configuration and load the file into the namespace. If this is not the behaviour you want, use a `ConfigurationWatcher` instead.

  Usage:

      import staticconf

      watcher = staticconf.ConfigFacade.load(
          'config.yaml', # Filename or list of filenames to watch
          'my_namespace',
          staticconf.YamlConfiguration, # Callable which takes the filename
          min_interval=3 # Wait at least 3 seconds before checking modified time
      )

      watcher.add_callback('identifier', do_this_after_reload)
      watcher.reload_if_changed()

  classmethod load(filename: str, namespace: str, loader_func: LoadFunc, min_interval: float = 0, comparators: Optional[List[Type[IComparator]]] = None) → ConfigFacade

    Create a new `ConfigurationWatcher` and load the initial configuration by calling loader_func.

    Parameters:

      - filename – a filename or list of filenames to monitor for changes

      - namespace – the name of a namespace to use when loading configuration. All config data from filename will end up in a `ConfigNamespace` with this name

      - loader_func – a function which accepts two arguments and uses loader functions from `staticconf.loader` to load configuration data into a namespace. The arguments are filename and namespace

      - min_interval – minimum number of seconds to wait between calls to `os.path.getmtime()` to check if a file has been modified.

      - comparators – a list of classes which support the `IComparator` interface which are used to determine if a config file has been modified. See ConfigurationWatcher::__init__.

    Returns:

      a `ConfigFacade`

  reload_if_changed(force: bool = False) → None

    See `ConfigurationWatcher.reload_if_changed()`

class staticconf.config.ConfigNamespace(name: str)

  A container for related configuration values. Values are stored using flattened keys which map to values.

  Values are added to this container using `staticconf.loader`. When a `ConfigNamespace` is created, it persists for the entire life of the process. Values will stay in the namespace until `clear()` is called to remove them.

  To retrieve a namespace, use `get_namespace()`.

  To access values stored in this namespace use `staticconf.readers` or `staticconf.schema`.

  clear() → None

    Remove all values from the namespace.

  get_config_dict() → Dict[str, Any]

    Reconstruct the nested structure of this object’s configuration and return it as a dict.

  get_config_values() → Dict[str, Any]

    Return all configuration stored in this object as a dict.

class staticconf.config.ConfigurationWatcher(config_loader: Callable[[], Dict[str, Any]], filenames: Union[str, List[str]], min_interval: float = 0, reloader: Optional[Reloader] = None, comparators: Optional[List[Type[IComparator]]] = None)

  Watches a file for modification and reloads the configuration when it’s modified. Accepts a min_interval to throttle checks.

  The default `reload()` operation is to reload all namespaces. To only reload a specific namespace use a `ReloadCallbackChain` for the reloader.

  See also

  `ConfigFacade.load()` which provides a more concise interface for the common case.

  Usage:

      import staticconf
      from staticconf import config

      def build_configuration(filename, namespace):
          config_loader = partial(staticconf.YamlConfiguration,
                                  filename, namespace=namespace)
          reloader = config.ReloadCallbackChain(namespace)
          return config.ConfigurationWatcher(
              config_loader, filename, min_interval=2, reloader=reloader)

      config_watcher = build_configuration('config.yaml', 'my_namespace')

      # Load the initial configuration
      config_watcher.config_loader()

      # Do some work
      for item in work:
          config_watcher.reload_if_changed()
          ...

  Parameters:

    - config_loader – a function which takes no arguments. It is called by `reload_if_changed()` if the file has been modified

    - filenames – a filename or list of filenames to watch for modifications

    - min_interval – minimum number of seconds to wait between calls to `os.path.getmtime()` to check if a file has been modified.

    - reloader – a function which is called after config_loader when a file has been modified. Defaults to an empty `ReloadCallbackChain`

    - comparators – a list of classes which support the `IComparator` interface which are used to determine if a config file has been modified. Defaults to `MTimeComparator`.

  reload_if_changed(force: bool = False) → Optional[Dict[str, Any]]

    If the file(s) being watched by this object have changed, their configuration will be loaded again using config_loader. Otherwise this is a noop.

    Parameters:

      force – If True ignore the min_interval and proceed to file modified comparisons. To force a reload use `reload()` directly.

class staticconf.config.IComparator(filenames: List[str])

  Interface for a comparator which is used by `ConfigurationWatcher` to determine if a file has been modified since the last check. A comparator is used to reduce the work required to reload configuration. Comparators should implement a mechanism that is relatively efficient (and scalable), so it can be performed frequently.

  Parameters:

    filenames – A list of absolute paths to configuration files.

  has_changed() → bool

    Returns True if any of the files have been modified since the last call to `has_changed()`. Returns False otherwise.

class staticconf.config.InodeComparator(filenames: List[str])

  Compare files by inode and device number. This is a good comparator to use when your files can change multiple times per second.

  has_changed() → bool

    Returns True if any of the files have been modified since the last call to `has_changed()`. Returns False otherwise.

class staticconf.config.MD5Comparator(filenames: str)

  Compare files by md5 hash of their contents. This comparator will be slower for larger files, but is more resilient to modifications which only change mtime, but not the files contents.

  has_changed() → bool

    Returns True if any of the files have been modified since the last call to `has_changed()`. Returns False otherwise.

class staticconf.config.MTimeComparator(filenames: List[str], compare_func: Optional[Callable[[str], bool]] = None)

  Compare files by modified time, or using compare_func, if it is not None.

  Note

  Most filesystems only store modified time with second grangularity so multiple changes within the same second can be ignored.

  has_changed() → bool

    Returns True if any of the files have been modified since the last call to `has_changed()`. Returns False otherwise.

class staticconf.config.ReloadCallbackChain(namespace: str = 'DEFAULT', all_names: bool = False, callbacks: List[Tuple[str, Callable[[], None]]] = None)

  A chain of callbacks which will be triggered after configuration is reloaded. Designed to work with `ConfigurationWatcher`.

  When this class is called it performs two operations:

  - calls `reload()` on the namespace

  - calls all attached callbacks

  Usage:

      chain = ReloadCallbackChain()
      chain.add('some_id', callback_foo)
      chain.add('other_id', other_callback)
      ...

      # some time later
      chain.remove('some_id')

  Parameters:

    - namespace – the name of the namespace to `reload()`

    - all_names – if True `reload()` all namespaces and ignore the namespace param. Defaults to False

    - callbacks – initial list of tuples to add to the callback chain

staticconf.config.get_namespace(name: str) → ConfigNamespace

  Return a `ConfigNamespace` by name, creating the namespace if it does not exist.

staticconf.config.reload(name: str = 'DEFAULT', all_names: bool = False) → None

  Reload one or all `ConfigNamespace`. Reload clears the cache of `staticconf.schema` and `staticconf.getters`, allowing them to pickup the latest values in the namespace.

  Defaults to reloading just the DEFAULT namespace.

  Parameters:

    - name – the name of the `ConfigNamespace` to reload

    - all_names – If True, reload all namespaces, and ignore name

staticconf.config.validate(name: str = 'DEFAULT', all_names: bool = False) → None

  Validate all registered keys after loading configuration.

  Missing values or values which do not pass validation raise `staticconf.errors.ConfigurationError`. By default only validates the DEFAULT namespace.

  Parameters:

    - name (string) – the namespace to validate

    - all_names (boolean) – if True validates all namespaces and ignores name

staticconf.config.view_help() → str

  Return a help message describing all the statically configured keys.

## Errors

exception staticconf.errors.ConfigurationError

  Thrown when there is an error loading configuration from a file or object.

exception staticconf.errors.ValidationError

  Thrown when a configuration value can not be coerced into the expected type by a validator.