Configuration File Details
Let’s explore the details of how the configuration file works!
The configuration file edited by the user (~/cea.config
) is only the tip of the iceberg, resting on a foundation
of the default configuration file default.config
file and the class cea.config.Configuration
, which
reads in the default configuration file as well as the user configuration file and makes those parameters available to
the scripts. Each script is provided with an instance of cea.config.Configuration
called config
.
Each parameter is defined in a section. Each parameter has a type, which specifies the range of values allowed for that parameter and also how to read and write them to the configuration file.
Access to parameters through the config
variable happens by section. Since all section names and parameter names
in the configuration file follow the kebab-case naming convention, and these are not valid python identifiers, a
translation is made to the snake_case naming convention: All hyphens (-
) are replaced by underscores (_
).
The syntax is simple:
"config." + [section] + "." + parameter
The section name is optional for the section general
, so config.general.scenario
refers to the same parameter as
config.scenario
. Note that these parameters can also be set:
config.scenario = r'C:\hoenggerberg\baseline'
If you want to persist these changes to disk, you need to explicitly save them with
cea.config.Configuration.save()
.
Note
It is a bad idea to have multiple instances of cea.config.Configuration
, as if one part of a
script changes a parameter, this will not be reflected in the other instances. Each CEA script accepts a config
argument to it’s main
function and should only use that.
Overview
digraph config { graph [splines=ortho, nodesep=0.1, rankdir="TD"] node [shape="record", fontname="Arial", fontsize="8"] Configuration -> Section [label=" 0..*"]; Section -> Parameter [label=" 0..*"]; Configuration [label="{Configuration|default_config\luser_config\lsections\l|apply_command_line_args()\lsave()\l}"]; Parameter [label="{Parameter|name\lhelp\lcategory\lsection\lconfig\l|initialize()\lget()\lset()\lencode()\ldecode()\l}"]; Section [label="{Section|name\lconfig\lparameters\l|__getattr__()\l__setattr()__\l}"]; { rank="same"; Configuration; Section; Parameter; } }Initialization of the config object
An instance of cea.config.Configuration
is created with an optional config_file
parameter that specifies
the configuration file to load as the user configuration file. This defaults to ~/cea.config
. This file is parsed
as a ConfigParser.SafeConfigParser
, using the default configuration as a backup for the values and stored
in the attribute user_config
. Another ConfigParser.SafeConfigParser
is created for the default
configuration and stored in the attribute default_config
.
Next, the default_config
is used to create a dictionary of :py:class`cea.config.Section` objects and each section is
populated with a dictionary of cea.config.Parameter
instances. The default configuration file lists not only
each parameter, but additional keys for each parameter as well. Example:
[general]
scenario = C:\reference-case-open\baseline
scenario.type = PathParameter
scenario.help = Path to the scenario to run
Using this information, the parameter general:scenario
is assigned a default value of C:\reference-case-open\baseline
,
is represented by a subtype of cea.config.Parameter`
called cea.config.PathParameter
and has
a help text “Path to the scenario to run” - which is stored in the help
attribute of the parameter object.
Some subclasses of cea.config.Parameter
have additional configuration, like the cea.config.ChoiceParameter:
[data-helper]
region = CH
region.type = ChoiceParameter
region.choices = CH SIN custom
region.help = The region to use for the databases (either CH or SIN) - set to "custom" if you want to edit them
When the config
instance is creating the parameters, each parameter object is given a chance to initialize itself
with a call to cea.config.Parameter.initialize(parser)()
with parser
set to the default_config
.
Subclasses of Parameter
can override this method to read this additional configuration.
How a value is read from the config file
When a script does something like config.general.weather
, the config.sections
dictionary is checked for the
section named general
and the parameters
dictionary in that section is checked for a parameter named weather
.
The cea.config.Parameter.get()
method is called on that parameter and the result of this call is returned.
Based on the default configuration file, this is defined as:
[general]
weather = Zug-inducity_1990_2010_TMY
weather.type = WeatherPathParameter
weather.help = either a full path to a weather file or the name of one of the weather files shipped with the CEA
So the parameter is of type cea.config.WeatherPathParameter
.
Inside the cea.config.Parameter.get()
method, a call is made to cea.config.Parameter.decode()
, passing
in the value read from the user configuration file. Subclasses of Parameter
specify how to encode and decode values
to the configuration file. The semantics are:
decode
takes a string from a configuration file (or from the command line) and returns a typed value (e.g. abool
if the parameter type iscea.config.BooleanParameter
).encode
takes a typed value (e.g. a boolean value) and encodes it to a string that can be stored in the configuration file.
In the case of cea.config.WeatherPathParameter
, decode
will ensure that the path to the weather file
exists and, if just the name of a weather file in the CEA weather file database is returned, resolves that to the full
path to that file. Hence, on my system, the value of config.weather
is
C:\Users\darthoma\Documents\GitHub\CityEnergyAnalyst\cea\databases\weather\Zurich.epw
.
How a value is saved to the config file
The mechanism for saving a value to the config file works similarly: cea.config.Parameter.set()
is called,
which in turn calls cea.config.Parameter.encode()
- subclasses can override this to provide type specific
behaviour.
How to create new parameter types
Steps:
subclass
cea.config.Parameter
optional: override
initialize
to settingsoptional: override
encode
to format the parameter value as a stringoptional: override
decode
to read the parameter value from a string
Check the existing parameter types for ideas!