Skip to content

Commit

Permalink
Take previous config platform_map into account.
Browse files Browse the repository at this point in the history
  • Loading branch information
bfloch committed Nov 5, 2019
1 parent f721d99 commit 112fc46
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 7 deletions.
18 changes: 12 additions & 6 deletions src/rez/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from rez import __version__
from rez.utils.data_utils import AttrDictWrapper, RO_AttrDictWrapper, \
convert_dicts, cached_property, cached_class_property, LazyAttributeMeta, \
deep_update, ModifyList
deep_update, ModifyList, HashableDict
from rez.utils.formatting import expandvars, expanduser
from rez.utils.logging_ import get_debug_printer
from rez.utils.scope import scoped_format
Expand Down Expand Up @@ -819,7 +819,7 @@ def _replace_config(other):


@lru_cache()
def _load_config_py(filepath):
def _load_config_py(filepath, fallback_platform_map):
from rez.utils.data_utils import Conditional, PlatformDependent, \
InConfigArchDependent, InConfigOsDependent
reserved = dict(
Expand All @@ -828,13 +828,14 @@ def _load_config_py(filepath):
# and later excluded from the `Config` class
__name__=os.path.splitext(os.path.basename(filepath))[0],
__file__=filepath,
__fallback_platform_map=fallback_platform_map,

rez_version=__version__,
ModifyList=ModifyList,
Conditional=Conditional,
PlatformDependent=PlatformDependent,
ArchDependent=InConfigArchDependent,
OsDependent=InConfigOsDependent
OsDependent=InConfigOsDependent,
)

g = reserved.copy()
Expand All @@ -851,14 +852,15 @@ def _load_config_py(filepath):
for k, v in g.items():
if k != '__builtins__' \
and not ismodule(v) \
and k not in reserved:
and k not in reserved \
and k != "__fallback_platform_map":
result[k] = v

return result


@lru_cache()
def _load_config_yaml(filepath):
def _load_config_yaml(filepath, _):
with open(filepath) as f:
content = f.read()
try:
Expand Down Expand Up @@ -890,7 +892,11 @@ def _load_config_from_filepaths(filepaths):
if not os.path.isfile(filepath_with_ext):
continue

data_ = loader(filepath_with_ext)
previous_platform_map = data.get("platform_map", None)
if previous_platform_map is not None:
previous_platform_map = HashableDict(previous_platform_map)

data_ = loader(filepath_with_ext, previous_platform_map)
deep_update(data, data_)
sourced_filepaths.append(filepath_with_ext)
break
Expand Down
4 changes: 4 additions & 0 deletions src/rez/tests/data/config/test_conditional_dependee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

dot_image_format = ArchDependent({
"IMPOSSIBLE_ARCH": "hello",
})
31 changes: 31 additions & 0 deletions src/rez/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ def _test_basic(self, c):
# plugin settings common to a plugin type
self.assertEqual(type(p.release_vcs.tag_name), str)

def test_hashabledict(self):
# Make sure that hashes matches even on dicts with different order.

from rez.utils.data_utils import HashableDict
from collections import OrderedDict

a = HashableDict(OrderedDict([("a", 1), ("b", 3)]))
b = HashableDict(OrderedDict([("b", 3), ("a", 1)]))
c = HashableDict(OrderedDict([("a", 1), ("c", 3)]))

self.assertEqual(a, b)
self.assertNotEqual(a, c)

with self.assertRaises(TypeError):
a["d"] = 5

self.assertEqual(a, b)

def _test_overrides(self, c):
c.override("debug_none", True)
c.override("build_directory", "floober")
Expand Down Expand Up @@ -139,6 +157,19 @@ def test_conditional_in_file(self):
self.assertEqual(c.prune_failed_graph, True)
self.assertEqual(c.warn_all, True)

def test_conidition_nested(self):
conf = os.path.join(self.config_path, "test_conditional.py")
conf_dependee = os.path.join(self.config_path, "test_conditional_dependee.py")
c = Config([conf, conf_dependee])
self.assertEqual(c.dot_image_format, "hello")

def test_conidition_nested_inbeween(self):
conf = os.path.join(self.config_path, "test_conditional.py")
conf_middle = os.path.join(self.config_path, "test2.py")
conf_dependee = os.path.join(self.config_path, "test_conditional_dependee.py")
c = Config([conf, conf_middle, conf_dependee])
self.assertEqual(c.dot_image_format, "hello")

def test_1(self):
"""Test just the root config file."""

Expand Down
41 changes: 40 additions & 1 deletion src/rez/utils/data_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Utilities related to managing data types.
"""
from collections import Mapping
from rez.exceptions import ConditionalConfigurationError
from rez.vendor.schema.schema import Schema, Optional
from rez.vendor.six import six
Expand Down Expand Up @@ -683,7 +684,10 @@ def __new__(cls, base, frame, options, default=ConditionalConfigurationError):
# a global config.
platform_map = frame.f_locals.get(
"platform_map",
None
frame.f_locals.get(
"__fallback_platform_map",
None
)
)

return base(options, default, platform_map=platform_map)
Expand Down Expand Up @@ -711,6 +715,41 @@ def __new__(cls, options, default=ConditionalConfigurationError):
default)


class HashableDict(Mapping):
"""
Immutable Hashable dict
Hash is based on key and value.
It supports nested dict-like values.
It does ignore any order of the items.
Could be replaced in future with:
https://www.python.org/dev/peps/pep-0603/#why-frozenmap-and-not-frozendict
"""

def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
self._hash = None

for k, v in self._d.items():
if isinstance(v, dict):
self._d[k] = HashableDict(v)

def __iter__(self):
return iter(self._d)

def __len__(self):
return len(self._d)

def __getitem__(self, key):
return self._d[key]

def __hash__(self):
return hash(
(frozenset(six.iteritems(self._d)), frozenset(six.itervalues(self._d)))
)


# Copyright 2013-2016 Allan Johns.
#
# This library is free software: you can redistribute it and/or
Expand Down

0 comments on commit 112fc46

Please sign in to comment.