Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds multiple merge in load/loads, implements tests and increments ve…
…rsion to 0.1.0
- Loading branch information
Showing
13 changed files
with
239 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from .import_module import import_module | ||
from .load import load, loads | ||
from .merge import merge | ||
from .propagate_defaults import propagate_defaults | ||
|
||
__all__ = [import_module, load, loads, merge, propagate_defaults] | ||
|
||
__version__ = "0.1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import importlib | ||
|
||
|
||
def import_module(path): | ||
""" | ||
Import a class or module from a path. E.g. | ||
``import_class("difflib.SequenceMatcher")`` returns a reference to the | ||
SequenceMatcher class. | ||
""" | ||
try: | ||
parts = path.split(".") | ||
module_path = ".".join(parts[:-1]) | ||
attribute_name = parts[-1] | ||
|
||
module = importlib.import_module(module_path) | ||
|
||
attribute = getattr(module, attribute_name) | ||
|
||
return attribute | ||
except AttributeError: | ||
return importlib.import_module(path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import io | ||
|
||
import yaml | ||
|
||
from .merge import merge | ||
from .propagate_defaults import propagate_defaults | ||
|
||
|
||
def load(*files): | ||
""" | ||
Loads configuration from one or more files by merging right to left. | ||
:Parameters: | ||
*files : `file-like` | ||
A YAML file to read. | ||
:Returns: | ||
`dict` : the configuration document | ||
""" | ||
doc = merge(*(yaml.load(f) for f in files)) | ||
return propagate_defaults(doc) | ||
|
||
|
||
def loads(*strings): | ||
""" | ||
Loads configuration from one or more files by merging right to left. | ||
:Parameters: | ||
*strings : `str` | ||
YAML strings to read. | ||
:Returns: | ||
`dict` : the configuration document | ||
""" | ||
return load(*(io.StringIO(s) for s in strings)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
def merge(d, *dicts): | ||
""" | ||
Recursively merges dictionaries | ||
""" | ||
|
||
for d_update in dicts: | ||
if not isinstance(d, dict): | ||
raise TypeError("{0} is not a dict".format(d)) | ||
|
||
dict_merge_pair(d, d_update) | ||
|
||
return d | ||
|
||
|
||
def dict_merge_pair(d1, d2): | ||
""" | ||
Recursively merges values from d2 into d1. | ||
""" | ||
for key in d2: | ||
if key in d1 and isinstance(d1[key], dict) and \ | ||
isinstance(d2[key], dict): | ||
dict_merge_pair(d1[key], d2[key]) | ||
else: | ||
d1[key] = d2[key] | ||
|
||
return d1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import copy | ||
|
||
from .merge import dict_merge_pair | ||
|
||
|
||
def propagate_defaults(config_doc): | ||
""" | ||
Propagate default values to sections of the doc. | ||
""" | ||
for group_name, group_doc in config_doc.items(): | ||
if isinstance(group_doc, dict): | ||
defaults = group_doc.get('defaults', {}) | ||
|
||
for item_name, item_doc in group_doc.items(): | ||
if item_name == 'defaults': | ||
continue | ||
if isinstance(item_doc, dict): | ||
|
||
group_doc[item_name] = \ | ||
dict_merge_pair(copy.deepcopy(defaults), item_doc) | ||
|
||
return config_doc |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
hats: | ||
red: | ||
color: red | ||
size: 10 | ||
bowler: | ||
color: black | ||
size: 25 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
hats: | ||
bowler: | ||
size: 35 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import os | ||
|
||
from nose.tools import eq_ | ||
|
||
from ..load import load, loads | ||
|
||
EXPECTED = { | ||
'hats': { | ||
'red': { | ||
'color': "red", | ||
'size': 10 | ||
}, | ||
'bowler': { | ||
'color': "black", | ||
'size': 35 | ||
} | ||
} | ||
} | ||
|
||
PWD = os.path.dirname(os.path.realpath(__file__)) | ||
|
||
|
||
def test_load(): | ||
|
||
eq_(load(open(os.path.join(PWD, 'config1.yaml')), | ||
open(os.path.join(PWD, 'config2.yaml'))), | ||
EXPECTED) | ||
|
||
eq_(loads(open(os.path.join(PWD, 'config1.yaml')).read(), | ||
open(os.path.join(PWD, 'config2.yaml')).read()), | ||
EXPECTED) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from nose.tools import eq_ | ||
|
||
from ..merge import merge | ||
|
||
|
||
def test_merge(): | ||
a = { | ||
'foo': { | ||
'bar': { | ||
'foo': 5, | ||
'bar': 7 | ||
} | ||
}, | ||
'l': [1, 5, 'foo'] | ||
} | ||
b = { | ||
'foo': { | ||
'bar': { | ||
'foo': 6 | ||
} | ||
}, | ||
'bar': 5, | ||
's': "I'm a string", | ||
'l': [1, 2, 3] | ||
} | ||
c = { | ||
'foo': { | ||
'bar': { | ||
'foobar': 10 | ||
} | ||
} | ||
} | ||
expected = { | ||
'foo': { | ||
'bar': { | ||
'foo': 6, | ||
'bar': 7, | ||
'foobar': 10 | ||
} | ||
}, | ||
'bar': 5, | ||
's': "I'm a string", | ||
'l': [1, 2, 3] | ||
} | ||
eq_(merge(a, b, c), | ||
expected) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from nose.tools import eq_ | ||
|
||
from ..propagate_defaults import propagate_defaults | ||
|
||
|
||
def test_propagate_defaults(): | ||
|
||
input = { | ||
'foos': { | ||
'defaults': { | ||
'bar': 1, | ||
'baz': 2 | ||
}, | ||
'1_foo': {}, | ||
'2_foo': { | ||
'baz': 3 | ||
} | ||
} | ||
} | ||
expected = { | ||
'foos': { | ||
'defaults': { | ||
'bar': 1, | ||
'baz': 2 | ||
}, | ||
'1_foo': { | ||
'bar': 1, | ||
'baz': 2 | ||
}, | ||
'2_foo': { | ||
'bar': 1, | ||
'baz': 3 | ||
} | ||
} | ||
} | ||
eq_(propagate_defaults(input), expected) |