Constants and Configuration¶
Content¶
1. Constants¶
Constants are values that, once initialized, are never changed during the runtime of a program. In Python constants are assigned to variables with capital letters by convention, and vice versa, variables with capital letters are supposed to be constants.
In principle there are about four ways to define a constant’s value: - hard coding: the value is defined in the python code directly - argument: the value is taken from an execution argument - context: the value is derived from the environmental context of the exection, e.g., the current working directory or the date-time of execution start. - configuation: read from a file or database
In CLIMADA, we only use hard coding and configuration to assign values to constants.
1.A. Hard Coded¶
Hard coding constants is the prefered way to deal with strings that are used to identify objects or files.
[22]:
# suboptimal
my_dict = {'x': 4}
if my_dict['x'] > 3:
msg = 'well, arh, ...'
msg
[22]:
'well, arh, ...'
[21]:
# good
X = 'x'
my_dict = {X: 4}
if my_dict[X] > 3:
msg = 'yeah!'
msg
[21]:
'yeah!'
[28]:
# possibly overdoing it
X = 'x'
Y = "this doesn't mean that every string must be a constant"
my_dict = {X: 4}
if my_dict[X] > 3:
msg = Y
msg
[28]:
"this doesn't mean that every string must be a constant"
[26]:
import pandas as pd
X = 'x'
df = pd.DataFrame({'x':[1,2,3], 'y':[4,5,6]})
try:
df.X
except:
from sys import stderr; stderr.write("this does not work\n")
df[X] # this does work but it's less pretty
df.x
this does not work
[26]:
0 1
1 2
2 3
Name: x, dtype: int64
1.B. Configurable¶
1.C. Where to put constants?¶
As a general rule, constants are defined in the module where they intrinsically belong to. If they belong equally to different modules though or they are meant to be used globally, there is the module climada.util.constants
which is compiling constants CLIMADA wide.
2. Configuration¶
2.A. Configuration files¶
climada.conf
. There is a default config file that comes with the installation of CLIMADA. But it’s possible to have several of them. In this case they are complementing one another.CLIMADA looks for configuration files upon import climada
. There are four loacations to look for configuration files: - climada/conf
, the installation directory - ~/climada/conf
, the user’s default climada directory - ~/.config
, the user’s configuration directory, - .
, the current working directory
At each location, the path is followed upwards until a file called climada.conf
is found or the root of the path is reached. Hence, if e.g., ~/climada/climada.conf
is missing but ~/climada.conf
is present, the latter would be read.
[..]/./climada.conf
> ~/.config/climada.conf
> ~/climada/conf/climada.conf
> installation_dir/climada/conf/climada.conf
my_config_value
that blongs to the module climada.util.dates_times
is wanted, it would be defined as{
"util": {
"dates_times": {
"my_config_value": 42
}
}
}
Configuration string values can be referenced from other configuration values. E.g.
{
"a": "x",
"b": "{a}y"
}
In this example “b” is eventually resolved to “xy”.
2.B. Accessing configuration values¶
Configuration values can be accessed through the (constant) CONFIG
from the climada
module:
[1]:
from climada import CONFIG
[3]:
CONFIG.hazard
[3]:
{drought: {resources: {spei_file_url: http://digital.csic.es/bitstream/10261/153475/8}}, landslide: {resources: {opensearch: https://pmmpublisher.pps.eosdis.nasa.gov/opensearch, climatology_monthly: https://svs.gsfc.nasa.gov/vis/a000000/a004600/a004631/frames/9600x5400_16x9_30p/MonthlyClimatology/[01-12]_ClimatologyMonthly_032818_9600x5400.tif}, local_data: .}, relative_cropyield: {local_data: ~/climada/data/ISIMIP_crop}, trop_cyclone: {random_seed: 54}}
The configuration itself and its attributes have the data type climada.util.config.Config
[12]:
CONFIG.__class__, CONFIG.hazard.trop_cyclone.random_seed.__class__
[12]:
(climada.util.config.Config, climada.util.config.Config)
The actual configuration values can be accessed as basic types (float, int, str), provided the definition is according to the respective data type:
[4]:
CONFIG.hazard.trop_cyclone.random_seed.int()
[4]:
54
[3]:
try:
CONFIG.hazard.trop_cyclone.random_seed.str()
except Exception as e:
from sys import stderr; stderr.write(f"cannot convert random_seed to str: {e}\n")
cannot convert random_seed to str: <class 'int'>, not str
However, configuration string values can be converted to pathlib.Path
objects if they are pointing to a directory.
[19]:
CONFIG.hazard.relative_cropyield.local_data.dir()
[19]:
WindowsPath('C:/Users/me/climada/data/ISIMIP_crop')
Note that converting a configuration string to a Path
object like this will create the specified directory on the fly, unless dir
is called with the parameter create=False
.
2.C. Default Configuration¶
climada/conf/climada.conf
contains the default configuration.~/climada/data
- demo: top directory for data that is downloaded or created in the CLIMADA tutorials~/climada/demo/data
- save_dir: directory where transient (non-persistent) data is stored./results
- log_level: minimum log level showed by logging, one of DEBUG, INFO, WARNING, ERROR or CRITICAL.INFO
- max_matrix_size: maximum matrix size that can be used, can be decreased in order to avoid memory issues100000000
(1e8) - exposures: exposures modules specific configuration - hazard: hazard modules specific configuration[5]:
CONFIG.__dict__.keys()
[5]:
dict_keys(['_root', '_comment', 'local_data', 'exposures', 'hazard', 'log_level', 'max_matrix_size'])
import climada
is executed in a python script or shell, data files from the installation directory are copied to the location specified int the current configuration.~/.config/climada.conf
with customized values for local_data.system
and local_data.demo
.{
"local_data": {
"system": "/path/to/installation-dir/climada/data/system",
"demo": "/path/to/installation-dir/climada/data/demo",
},
}
2.D. Test Configuration¶
climada.conf
file of the installation directory. This file contains pathes to files that are read during tests. If they are part of the GitHub repository, their path i.g. starts with the climada
folder within the installation directory:{
"_comment": "this is a climada configuration file meant to supersede the default configuration in climada/conf during test",
"test_directory": "./climada",
"test_data": "{test_directory}/test/data",
"disc_rates": {
"test_data": "{test_directory}/entity/disc_rates/test/data"
},
...
}
test_directory
is given as the relative path to ./climada
. This is fine if (but only if) unit or integration tests are started from the installation directory, which is the case in the automated tests on the CI server.{
"_comment": "this is a climada configuration file meant to supersede the default configuration in climada/conf during test",
"test_directory": "/path/to/installation-dir/climada",
"test_data": "{test_directory}/test/data",
"disc_rates": {
"test_data": "{test_directory}/entity/disc_rates/test/data"
},
...
}