def_file
Read, write, and modify *.def file from the IPSL/modipsl project.
The *.def file contains model parameters in the key-value format. The format
is extremely simple in comparison to similar formats, like *.ini or *.toml, as
it doesn't provide sections, nor standarized datatypes.
Usually, model configuration files contain dozens or hundred of parameters
with scalars (int, float, str), arrays, or special _AUTO_/_AUTOBLOCK_ values.
The special "auto" values are used by the IPSL/modipsl/libIGCM projects to mark place where an external script, called component driver, should inject configuration values.
Examples usage:
// Follows Python convention of the JSON module with load(), dump(), etc. functions
from ipsl_common.modipsl.def_file import load, dump
with open("run_dynamico.def", "r") as f:
parameters = load(f)
// Modify loaded parameters
parameters["start_file_name"] = "start2024.nc"
with open("new_run_dynamico.def", "w") as g:
dump(parameters, g)
Loading an example *.def file:
INCLUDEDEF=run_lmdz.def
INCLUDEDEF=run_dynamico.def
use_forcing=y
g=_AUTO_: DEFAULT=9.8
start_file_name=start2023
physics="always"
Gives the following dictionary:
{
'INCLUDEDEF': ['run_lmdz.def', 'run_dynamico.def'],
'g': ('_AUTO_', 9.8),
'physics': '"always"',
'start_file_name': 'start2023',
'use_forcing': True
}
Loaded configuration can be altered and subsequently dumped onto a file or into
a string. The configuration is easy to view and modify, because it is directly
decoded into a Python dictionary. The decoding and encoding process is managed
internally by DefFileDecoder and DefFileEncoder classes with decode() and
encode() methods.
Classes
DefFileDecoder
DefFileDecoder(include_positions: bool = False)
Bases: Transformer
Decoder performs translation from *.def file to a dictionary.
The translation rules are:
*.def |
Python | Comment |
|---|---|---|
| key-value | dict |
Including many key-value pairs and INCLUDEDEF |
| array | list |
Collection of at least 2 elements |
| string | str |
Unquoted and quoted (single or double) strings |
| integer number | int |
Standard integer values |
| real number | float |
Including scientific notation |
true/y |
True |
Case insensitive |
false/n |
False |
Case insensitive |
_AUTO_ |
tuple |
With optional default value |
_AUTOBLOCKER_ |
tuple |
With optional default value |
The first step of the decoder is parsing of *.def file. For this task Lark Earley
parser is used with a simple grammar expressed with EBNF notation. The *.def
grammer doesn't parse well with LALR(1) parser. The parsing produces a parse tree.
The second step transforms the parse tree into Python dictionary using translation rules mentioned in the above table. This transformation is based on a automated visitor pattern called Transformer, which produces the dictionary in a bottom-up manner.
Examples:
from ipsl_common.modipsl.def_file import DefFileDecoder
dictionary = DefFileDecoder().decode(text)
If text contains this *.def file:
radius=6.371229E6
g=9.80665
omega=_AUTO_: DEFAULT=7.292E-5
Then, Python dictionary would look as follows:
{
"radius": 6.371229e6,
"g": 9.80665,
"omega": ("_AUTO_", 7.292e-05),
}
Tip
By default, the result dictionary contains no information about textual
layout of the file. However, by using the argument include_positions=True,
it is possible to refine the dictionary with exact start/end positions of
each value as follows:
{
"radius": {"value": 6371229.0, "start_pos": 50, "end_pos": 60},
"g": {"value": 9.80665, "start_pos": 99, "end_pos": 106},
"omega": {"value": ("_AUTO_", 7.292e-05), "start_pos": 158, "end_pos": 182},
}
Initialize DefFileDecoder.
Parameters:
-
(include_positionsbool, default:False) –include textual positions of keys and values (offset from the start)
Source code in ipsl_common/modipsl/def_file.py
349 350 351 352 353 354 355 | |
Methods:
decode
decode(content: str) -> dict
Decode *.def content into dictionary.
Parameters:
-
(contentstr) –content of the
*.deffile
Returns:
-
dict(dict) –Decoded
*.deffile
Source code in ipsl_common/modipsl/def_file.py
357 358 359 360 361 362 363 364 365 366 367 | |
DefFileEncoder
DefFileEncoder(
truthy_value: str = "true", falsey_value: str = "false"
)
Encoder performs translation from a dictionary to *.def file.
The translation rules are:
| Python | *.def |
Comment |
|---|---|---|
dict |
key-value | Each INCLUDEDEF value translates to a single key-value |
list |
array | Of at least 2 elements |
str |
string | Quoted strings will contain explicit quote characters |
int |
integer number | --- |
float |
real number | Including scientific notation |
bool |
true/false |
Can be specified with encode arguments |
tuple |
_AUTO_/_AUTOBLOCKER_ |
With optional default value at second position in tuple |
The translation is straightforward, based on Python type a specific conversion is performed. No grammar, nor parse tree is used during this step.
Example:
from ipsl_common.modipsl.def_file import DefFileEncoder
text = DefFileEncoder().encode(dictionary)
If dictionary contains:
{
"radius": 6.371229e6,
"g": 9.80665,
"omega": ("_AUTO_", 7.292e-05),
}
Then, the encoded *.def file would look as follows:
radius = 6371229.0
g = 9.80665
omega = _AUTO_: DEFAULT=7.292e-05
Tip
Python representation of the *.def file doesn't contain any textual position of
particular elements (keys, values, comments, whitespaces, etc.), thus, re-encoding of
the exact input *.def file is impossible. In order to recreate the original file,
or modify a file while keeping the original comments, whitespaces, and order of elements,
use the designated modify functions.
Initialize DefFileEncoder.
Parameters:
-
(truthy_valuestr, default:'true') –label used to encode True
-
(falsey_valuestr, default:'false') –label used to encode False
Source code in ipsl_common/modipsl/def_file.py
510 511 512 513 514 515 516 517 518 519 520 521 522 | |
Methods:
encode
encode(obj: Any) -> str
Encode dictionary or other Python object into *.def file.
This function works not only on full decoded *.def files,
but it also work on particular Python object such as a list,
or a tuple. In such case, it will take the given object and apply
one of the encoding rules mentioned before.
Parameters:
-
(objAny) –dictionary or Python object
Returns:
-
str–Encoded text of a
*.deffile
Source code in ipsl_common/modipsl/def_file.py
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | |
Functions:
dump
dump(obj: dict, buffer: TextIOBase) -> None
Dump dictionary into *.def text/file buffer.
Parameters:
-
(objdict) –dictionary to dump to a file
-
(bufferTextIOBase) –text or file buffer for storing *.def file
Source code in ipsl_common/modipsl/def_file.py
103 104 105 106 107 108 109 110 111 112 | |
dumps
dumps(obj: dict) -> str
Dump dictionary into *.def string.
Parameters:
-
(objdict) –dictionary to dump to a file
Source code in ipsl_common/modipsl/def_file.py
115 116 117 118 119 120 121 | |
load
load(
buffer: TextIOBase,
include_positions: bool = False,
return_text: bool = False,
) -> dict | tuple[dict, str]
Load *.def text/file buffer into dictionary.
Parameters:
-
(bufferTextIOBase) –text or file buffer with the
*.deffile -
(include_positionsbool, default:False) –include textual positions of values
Returns:
-
dict(dict | tuple[dict, str]) –Loaded
*.deffile
Source code in ipsl_common/modipsl/def_file.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
loads
loads(text: str, include_positions: bool = False) -> dict
Load *.def file string into dictionary.
Parameters:
-
(textstr) –content of the
*.deffile -
(include_positionsbool, default:False) –include textual positions of values
Returns:
-
dict(dict) –Loaded
*.deffile
Source code in ipsl_common/modipsl/def_file.py
90 91 92 93 94 95 96 97 98 99 100 | |
modify
modify(
buffer: TextIOBase,
new_obj: dict,
buffer_out: TextIOBase | None = None,
insert_header: str = "",
) -> None
Modify *.def text/file buffer with minimal amount of changes.
The output text/file buffer follows changes made to new_obj representation of *.def file.
The modifications are performed, so that the minimal amount of changes is applied.
As a result, the diff between the old and new file content is minimal and no comments
or whitespaces are lost beyond what is neccessary. The new_obj can remove, modify,
and/or add new key-value pairs.
Parameters:
-
(bufferTextIOBase) –text or file buffer for reading the file (optionally to write to the file)
-
(new_objdict) –modified representation of the *.def file content
-
(buffer_outTextIOBase | None, default:None) –optional output buffer for writing the modified file content
-
(insert_headerstr, default:'') –optional header inserted before appended key-value pairs
Source code in ipsl_common/modipsl/def_file.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | |
modifys
modifys(
text: str, new_obj: dict, insert_header: str = ""
) -> str
Modify *.def file string with minimal amount of changes.
The output text follows changes made to new_obj representation of *.def file.
The modifications are performed, so that the minimal amount of changes is applied.
As a result, the diff between the old and new file content is minimal and no comments
or whitespaces are lost beyond what is neccessary. The new_obj can remove, modify,
and/or add new key-value pairs.
Parameters:
-
(textstr) –input text with *.def content to modify
-
(new_objdict) –modified representation of the *.def file content
-
(insert_headerstr, default:'') –optional header inserted before appended key-value pairs
Returns:
-
str(str) –Modified text
Source code in ipsl_common/modipsl/def_file.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | |