Skip to content

Instantly share code, notes, and snippets.

@omry
Created September 2, 2018 22:49
Show Gist options
  • Save omry/c5edf420b7c5a76e3724b42d95884e23 to your computer and use it in GitHub Desktop.
Save omry/c5edf420b7c5a76e3724b42d95884e23 to your computer and use it in GitHub Desktop.
goodconf
import io
import yaml
class GoodConf:
def __init__(self, yaml):
if yaml is None:
self.yaml = ''
else:
self.yaml = yaml
# return a ConfigAccess to the result, or the actual result if it's a leaf in yaml
def __getattr__(self, key):
if type(self.yaml) == dict:
x = self.yaml.get(key)
if type(x) == dict:
return GoodConf(x)
else:
return x
elif type(self.yaml) == str:
return self.yaml
elif type is None:
return None
def __str__(self):
return self.yaml.__str__()
def __repr__(self):
return self.yaml.__repr__()
# Allow debugger to autocomplete correct fields
def __dir__(self):
if self.yaml is None:
return []
elif type(self.yaml) == dict:
return self.yaml.keys()
else:
return [self.yaml]
def __eq__(self, other):
return other == self.yaml
def update_key(self, key, value=None):
# Empty, either set key as node or new map with key:value
if self.is_empty():
if value is None:
self.yaml = key
else:
self.yaml = {key: value}
else:
if value is None:
# replace with value
self.yaml = key
else:
# we have new key:value and we are not empty
if type(self.yaml) == dict:
self.yaml[key] = value
elif type(self.yaml) == str:
# Promote to map if this is actually a change
if self.yaml != key:
self.yaml = {self.yaml: None}
self.yaml[key] = value
else:
raise AssertionError("Unsupported state")
def update(self, key, value=None):
split = key.split('.')
for i,k in enumerate(split):
if i == len(split) - 1:
self.update_key(k, value)
else:
self.update_key(k)
def is_empty(self):
return self.yaml == ''
class Config(GoodConf):
@staticmethod
def from_file(filename):
return GoodConf(yaml.load(io.open(filename, 'r')))
@staticmethod
def from_string(content):
return GoodConf(yaml.load(content))

goodconf

Goodconf is a yaml based configuration library, supporting dot access, deep updates and more.

Loading from a string:

    s = 'hello: world'
    c = Config.from_string(s)
    assert c.hello == 'world'
    assert c == {'hello': 'world'}

Loading from a file: config.yaml:

env_name: 'MBRLCartpole-v0'
num_trials: 1
train_timesteps: 200
render: False

training:
  batch_size: 128
c = Config.from_file('conf/config.yaml')
assert c.env_name == 'MBRLCartpole-v0'
assert c.training == 128

You can override configuration values:

c = config.Config.from_file('conf/config.yaml')
c.update('env_name', 'NewEnv-v2')
c.update('training.batch_size', 256)
from config import Config
def test_value():
s = 'hello'
c = Config.from_string(s)
assert c == s
def test_key_value():
s = 'hello: world'
c = Config.from_string(s)
assert c.hello == 'world'
assert c == {'hello': 'world'}
def test_empty_input():
s = ''
c = Config.from_string(s)
assert c == ''
def test_update_empty_to_value():
s = ''
c = Config.from_string(s)
c.update('hello')
assert c == 'hello'
def test_update_same_value():
s = 'hello'
c = Config.from_string(s)
c.update('hello')
assert c == 'hello'
def test_update_value_to_map():
s = 'hello'
c = Config.from_string(s)
c.update('hi', 'there')
assert c.hello is None
assert c.hi == 'there'
def test_update_map_empty_to_map():
s = ''
c = Config.from_string(s)
c.update('hello', 'there')
assert c == {'hello': 'there'}
def test_update__map_value():
# Replacing an existing key in a map
s = 'hello: world'
c = Config.from_string(s)
c.update('hello', 'there')
assert c == {'hello': 'there'}
def test_update_map_new_keyvalue():
# Adding another key to a map
s = 'hello: world'
c = Config.from_string(s)
c.update('who', 'goes there')
assert c == {'hello': 'world', 'who': 'goes there'}
def test_update_map_to_value():
# changing map to single node
s = 'hello: world'
c = Config.from_string(s)
c.update('value')
assert c == 'value'
def test_update_with_empty_map_value():
c = Config.from_string('')
c.update('a', {})
assert c == {'a': {}}
def test_update_with_map_value():
c = Config.from_string('')
c.update('a', {'aa': 1, 'bb': 2})
assert c == {'a': {'aa': 1, 'bb': 2}}
def test_update_deep_from_empty():
c = Config.from_string('')
c.update('a.b', 1)
assert c == {'a': None, 'b': 1}
def test_update_deep_with_map():
c = Config.from_string('a: b')
c.update('a.b', {'c': 'd'})
assert c == {'a': None, 'b': {'c': 'd'}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment