Skip to content

Commit

Permalink
Introduce nested version syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
frthjf committed Nov 24, 2020
1 parent 99cae54 commit ec63acb
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 33 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

<!-- Please add changes under the Unreleased section that reads 'No current changes' otherwise -->

# v2.9.1

- New nested version syntax `~nested:version`

# v2.9.0

- Resolve @-directives relative to `_machinable` module rather than top project level
Expand Down
45 changes: 21 additions & 24 deletions src/machinable/config/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .parser import parse_mixins


def collect_updates(version):
def _collect_updates(version):
collection = []
for update in version:
arguments = update["arguments"]
Expand Down Expand Up @@ -42,7 +42,7 @@ def __init__(self, parsed_config, version=None, default_class=None):
self.default_class = default_class
self.schema_validation = get_settings()["schema_validation"]

def _get_version(self, name, config, current=None):
def _get_version(self, name, config):
# from yaml file
if name.endswith(".yaml") or name.endswith(".json"):
with open(name) as f:
Expand All @@ -63,24 +63,22 @@ def _get_version(self, name, config, current=None):
return yaml.load(name, Loader=yaml.FullLoader)

# from local version
if name in config:
version = copy.deepcopy(config[name])
if not current:
return version
else:
# nested lookup
try:
return update_dict(copy.deepcopy(current[name]), version)
except KeyError:
return version

if current:
# nested lookup
try:
return copy.deepcopy(current[name])
except KeyError:
# ignore non-existing nested lookups
return {}
version = {}
path = name[1:].split(":")
level = config
try:
for key in path:
level = level["~" + key]
# extract config on this level
u = {
k: copy.deepcopy(v)
for k, v in level.items()
if not k.startswith("~")
}
version = update_dict(version, u)
return version
except KeyError:
pass

raise KeyError(
f"Version '{name}' could not be found.\n"
Expand Down Expand Up @@ -252,8 +250,7 @@ def get_component(self, name, version=None, flags=None):
versions.append({"arguments": {"components": copy.deepcopy(version)}})

version = {}
for updates in collect_updates(versions):
# select components/node subsection
for updates in _collect_updates(versions):
update = updates.get("components", None)
if update is None:
continue
Expand All @@ -267,7 +264,7 @@ def get_component(self, name, version=None, flags=None):
# load arguments from machinable.yaml
if isinstance(k, str):
config["versions"].append(k)
k = self._get_version(k, config["args"], version)
k = self._get_version(k, config["args"])
elif isinstance(k, dict):
# evaluate computed properties
for key in k.keys():
Expand All @@ -287,7 +284,7 @@ def get_component(self, name, version=None, flags=None):

# remove unused versions
config["args"] = {
k: v if not k.startswith("~") else "_"
k: v if not k.startswith("~") else ":"
for k, v in config["args"].items()
if not k.startswith("~") or k in config["versions"]
}
Expand Down
15 changes: 8 additions & 7 deletions tests/config/config_interface_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,24 @@ def test_config_versioning():
assert e["beta"]["test"]

# nested
t = Experiment().components(("thenode", ("~three", "~nested")))
t = Experiment().components(("thenode", "~three:nested"))
e, m = to_config(test_project, t)
assert e["works"]
assert e["nested"]
assert e["unaffected"] == "value"
assert e["nested"] is None
assert e["alpha"] == 4
assert e["beta"] == "nested"
assert "should_not_be" not in e

t = Experiment().components(("thenode", ("~two", "~nested")))
e, m = to_config(test_project, t)
assert e["alpha"] == 2
assert e["nested"]
assert e["nested"] is True

t = Experiment().components(("thenode", ("~three", "~nested", "~nestednested")))
t = Experiment().components(("thenode", ("~three:nested:nestednested")))
e, m = to_config(test_project, t)
assert e["works"]
assert e["unaffected"] == "value"
assert e["works"] is False
assert e["alpha"] == 5
assert e["q"] == -1
assert e["beta"] == "overwritten"
assert e["added"] == "value"

Expand Down
6 changes: 4 additions & 2 deletions tests/test_project/machinable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ components:
works:
nested:
added:
unaffected: true
q:
key:
mixing:
Expand All @@ -42,6 +43,7 @@ components:
alpha: 2
~three:
alpha: 3
unaffected: value
~nested:
works: False
alpha: 4
Expand All @@ -50,8 +52,8 @@ components:
beta: overwritten
alpha: 5
added: value
~nestednested:
q: -1
~second_nested:
should_not_be: selected
~nested:
nested: True
works: True
Expand Down

0 comments on commit ec63acb

Please sign in to comment.