Implementing custom ConfigSource classes¶
If you want to get configuration settings from some other sources than
the built-in sources, you should create a class that derives from
ConfigSource
and implement a few
methods.
If your chosen source can expose the settings as a (possibly nested)
dict
, it might be easier to derive from
DictSource
which already provide
implementations of many methods.
-
class
layeredconfig.
ConfigSource
(**kwargs)[source]¶ The constructor of the class should set up needed resources, such as opening and parsing a configuration file.
It is a good idea to keep whatever connection handles, data access objects, or other resources needed to retrieve the settings, as unprocessed as possible. The methods that actually need the data (
has()
,get()
,subsection()
,subsections()
and possiblytyped()
) should use those resources directly instead of reading from cached locally stored copies.The constructor must call the superclass’
__init__
method with all remaining keyword arguments, ie.super(MySource, self).__init__(**kwargs)
.-
dirty
= False¶ For writable sources, whether any parameter value in this source has been changed so that a call to
save()
might be needed.
-
identifier
= None¶ A string identifying this source, primarily used with
LayeredConfig.set()
.
-
writable
= False¶ Whether or not this source can accept changed configuration settings and store them in the same place as the original setting came from.
-
parent
= None¶ The parent of this source, if this represents a nested configuration source, or None
-
source
= None¶ By convention, this should be your main connection handle, data access object, or other resource neededed to retrieve the settings.
-
has
(key)[source]¶ This method should return true if the parameter identified by
key
is present in this configuration source. It is up to each configuration source to define the semantics of what exactly “is present” means, but a guideline is that only real values should count as being present. If you only have some sort of placeholder or typing information forkey
this should probably not return True.Note that it is possible that a configuration source would return True for
typed(some_key)
and at the same time return False forhas(some_key)
, if the source only carries typing information, not real values.
-
get
(key)[source]¶ Should return the actual value of the parameter identified by
key
. Ifhas(some_key)
returns True,get(some_key)
should always succeed. If the configuration source does not include intrinsic typing information (ie. everything looks like a string) this method should return the string as-is, LayeredConfig is responsible for converting it to the correct type.
-
typed
(key)[source]¶ Should return True if this source contains typing information for
key
, ie information about which data type this parameter should be.For sources where everything is stored as a string, this should generally return False (no way of distinguishing an actual string from a date formatted as a string).
-
subsections
()[source]¶ Should return a list (or other iterator) of subsection keys, ie names that represent subsections of this configuration source. Not all configuration sources need to support subsections. In that case, this should just return an empty list.
-
subsection
(key)[source]¶ Should return the subsection identified by
key
, in the form of a new object of the same class, but initialized differently. Exactly how will depend on the source, but as a general rule the same resource handle used asself.source
should be passed to the new object. Often, the subsection key will need to be provided to the new object as well, so thatget()
and other methods can use it to look in the correct place.As a general rule, the constructor should be called with a
parent
parameter set toself
.
-
set
(key, value)[source]¶ Should set the parameter identified by
key
to the new valuevalue
.This method should be prepared for any type of value, ie ints, lists, dates, bools… If the backend cannot handle the given type, it should convert to a str itself.
Note that this does not mean that the changes should be persisted in the backend data, only in the existing objects view of the data (only when
save()
is called, the changes should be persisted).
-
setup
(config)[source]¶ Perform some post-initialization setup. This method will be called by the LayeredConfig constructor after its internal initialization is finished, with itself as argument. Sources may access all properties of the config object in order to eg. find out which parameters have been defined.
The sources will be called in the same order as they were provided to the LayeredConfig constructior, ie. lowest precedence first.
Parameters: config (layeredconfig.LayeredConfig) – The initialized config object that this source is a part of
-
save
()[source]¶ Persist changed data to the backend. This generally means to update a loaded configuration file with all changed data, or similar.
This method will only ever be called if
writable
is True, and only ifdirty
has been set to True.If your source is read-only, you don’t have to implement this method.
-
-
class
layeredconfig.
DictSource
(**kwargs)[source]¶ If your backend data is exposable as a python dict, you can subclass from this class to avoid implementing
has()
,get()
,keys()
,subsection()
andsubsections()
. You only need to write__init__()
(which should setself.source
to that exposed dict), and possiblytyped()
andsave()
.-
subsections
()[source]¶ Should return a list (or other iterator) of subsection keys, ie names that represent subsections of this configuration source. Not all configuration sources need to support subsections. In that case, this should just return an empty list.
-
subsection
(key)[source]¶ Should return the subsection identified by
key
, in the form of a new object of the same class, but initialized differently. Exactly how will depend on the source, but as a general rule the same resource handle used asself.source
should be passed to the new object. Often, the subsection key will need to be provided to the new object as well, so thatget()
and other methods can use it to look in the correct place.As a general rule, the constructor should be called with a
parent
parameter set toself
.
-
typed
(key)[source]¶ Should return True if this source contains typing information for
key
, ie information about which data type this parameter should be.For sources where everything is stored as a string, this should generally return False (no way of distinguishing an actual string from a date formatted as a string).
-
has
(key)[source]¶ This method should return true if the parameter identified by
key
is present in this configuration source. It is up to each configuration source to define the semantics of what exactly “is present” means, but a guideline is that only real values should count as being present. If you only have some sort of placeholder or typing information forkey
this should probably not return True.Note that it is possible that a configuration source would return True for
typed(some_key)
and at the same time return False forhas(some_key)
, if the source only carries typing information, not real values.
-
get
(key)[source]¶ Should return the actual value of the parameter identified by
key
. Ifhas(some_key)
returns True,get(some_key)
should always succeed. If the configuration source does not include intrinsic typing information (ie. everything looks like a string) this method should return the string as-is, LayeredConfig is responsible for converting it to the correct type.
-
set
(key, value)[source]¶ Should set the parameter identified by
key
to the new valuevalue
.This method should be prepared for any type of value, ie ints, lists, dates, bools… If the backend cannot handle the given type, it should convert to a str itself.
Note that this does not mean that the changes should be persisted in the backend data, only in the existing objects view of the data (only when
save()
is called, the changes should be persisted).
-