fym.parser module¶
This module assists setting up the configuration of each module and scripts. It
parses JSON files with dot notation such as settings.json in Visual Studio
Code.
Basic Usage¶
parser.parse¶
parser.parse parses a JSON-like dict object to a nested
types.SimpleNamespace
object like following. It encodes a dotted key into a nested structure to make
ease of grouping the configuration.
from fym import parser, BaseEnv, BaseSystem
json_dict = {
"env.kwargs": dict(dt=0.01, max_t=10),
"multicopter.nrotor": 6,
"multicopter.m": 3.,
"multicopter.LQRGain": {
"Q": [1, 1, 1, 1],
"R": [1, 1],
},
"actuator.tau": 1e-1,
}
cfg = parser.parse(json_dict)
parser.update¶
Because the parser.parse method returns a SimpleNamespace instance,
the object should be updated or modified following the SimpleNamespace’s
rule. To make ease of usage, fym.parser module provides a convenient method,
parser.update, which can take a JSON-like dict with dotted keys or
another SimpleNamespace instance. See the following example.
cfg = parser.parse()
def load_config():
parser.update(cfg, {
"env.kwargs": dict(dt=0.01, max_t=10),
"agent.memory_size": 1000,
"agent.minibatch_size": 32,
})
load_config()
cfg.env.kwargs.dt = 0.001
The prune keyword¶
If you pass a prune=True keyword argument to update method, it will remove
the items that exist only in the first argument. It is extremely useful when
one need to reset a configuration without losing the reference.
config.pyfrom fym import parser default_cfg = parser.parse({"k1": 1, "k2": 2}) cfg = parser.copy(default_cfg)
foo.pyfrom fym import parser import config cfg = config.cfg def bar(): print(cfg)
main.pyfrom fym import parser import foo import config cfg = config.cfg def main(): # With prune=False (default) parser.update(cfg, {"k1": 2, "k3": 3}) foo.bar() # k1: 2, k2: 2, k3: 3 parser.update(cfg, config.default_cfg) foo.bar() # k1: 1, k2: 2, k3: 3 # With prune=True parser.update(cfg, {"k1": 2, "k3": 3}) parser.update(cfg, config.default_cfg, prune=True) foo.bar() # k1: 1, k2: 2 if __name__ == "__main__": main()
As you can see, the reference in foo.cfg is not broken. This concept can be
used to setup one default configuration, and several per-experiment,
use-defined configurations.
parser.decode¶
Note that all the child elements in the returned SimpleNamespace is also a
SimpleNamespace. A common method to conert it into a dict is vars,
although it cannot handle the nested dict. fym.parser module module provides a
parser.decode method that converts the nested SimpleNamespace object
into a nested dict which may useful to deal with keyword arguments.
cfg = parser.parse()
parser.update(cfg, {"env.kwargs": dict(dt=0.01, max_t=10)})
env = BaseEnv(**parser.decode(cfg.env.kwargs))
parser.merge¶
This is a recursively merging method for dict-like objects.
a = parser.parse({"env.kwargs": dict(dt=0.01, max_t=10)})
b = parser.parse({"env.kwargs.dt": 0.05, "env.loggerPath": "data.h5"})
Now, two SimpleNamespaces, a and b, can be merged through:
c = parser.merge(a, b)
The result is given by
{
env: {
kwargs: {
dt: 0.05,
max_t: 10,
},
loggerPath: data.h5,
},
}
parser.copy¶
This is a nothing but a deepcopy of the dict-like object. Hence, it breaks
the references.
def copy(d):
return deepcopy(parse(d))