Skip to content

Commit 112fc46

Browse files
committed
Take previous config platform_map into account.
1 parent f721d99 commit 112fc46

File tree

4 files changed

+87
-7
lines changed

4 files changed

+87
-7
lines changed

src/rez/config.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from rez import __version__
33
from rez.utils.data_utils import AttrDictWrapper, RO_AttrDictWrapper, \
44
convert_dicts, cached_property, cached_class_property, LazyAttributeMeta, \
5-
deep_update, ModifyList
5+
deep_update, ModifyList, HashableDict
66
from rez.utils.formatting import expandvars, expanduser
77
from rez.utils.logging_ import get_debug_printer
88
from rez.utils.scope import scoped_format
@@ -819,7 +819,7 @@ def _replace_config(other):
819819

820820

821821
@lru_cache()
822-
def _load_config_py(filepath):
822+
def _load_config_py(filepath, fallback_platform_map):
823823
from rez.utils.data_utils import Conditional, PlatformDependent, \
824824
InConfigArchDependent, InConfigOsDependent
825825
reserved = dict(
@@ -828,13 +828,14 @@ def _load_config_py(filepath):
828828
# and later excluded from the `Config` class
829829
__name__=os.path.splitext(os.path.basename(filepath))[0],
830830
__file__=filepath,
831+
__fallback_platform_map=fallback_platform_map,
831832

832833
rez_version=__version__,
833834
ModifyList=ModifyList,
834835
Conditional=Conditional,
835836
PlatformDependent=PlatformDependent,
836837
ArchDependent=InConfigArchDependent,
837-
OsDependent=InConfigOsDependent
838+
OsDependent=InConfigOsDependent,
838839
)
839840

840841
g = reserved.copy()
@@ -851,14 +852,15 @@ def _load_config_py(filepath):
851852
for k, v in g.items():
852853
if k != '__builtins__' \
853854
and not ismodule(v) \
854-
and k not in reserved:
855+
and k not in reserved \
856+
and k != "__fallback_platform_map":
855857
result[k] = v
856858

857859
return result
858860

859861

860862
@lru_cache()
861-
def _load_config_yaml(filepath):
863+
def _load_config_yaml(filepath, _):
862864
with open(filepath) as f:
863865
content = f.read()
864866
try:
@@ -890,7 +892,11 @@ def _load_config_from_filepaths(filepaths):
890892
if not os.path.isfile(filepath_with_ext):
891893
continue
892894

893-
data_ = loader(filepath_with_ext)
895+
previous_platform_map = data.get("platform_map", None)
896+
if previous_platform_map is not None:
897+
previous_platform_map = HashableDict(previous_platform_map)
898+
899+
data_ = loader(filepath_with_ext, previous_platform_map)
894900
deep_update(data, data_)
895901
sourced_filepaths.append(filepath_with_ext)
896902
break
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
dot_image_format = ArchDependent({
3+
"IMPOSSIBLE_ARCH": "hello",
4+
})

src/rez/tests/test_config.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@ def _test_basic(self, c):
3434
# plugin settings common to a plugin type
3535
self.assertEqual(type(p.release_vcs.tag_name), str)
3636

37+
def test_hashabledict(self):
38+
# Make sure that hashes matches even on dicts with different order.
39+
40+
from rez.utils.data_utils import HashableDict
41+
from collections import OrderedDict
42+
43+
a = HashableDict(OrderedDict([("a", 1), ("b", 3)]))
44+
b = HashableDict(OrderedDict([("b", 3), ("a", 1)]))
45+
c = HashableDict(OrderedDict([("a", 1), ("c", 3)]))
46+
47+
self.assertEqual(a, b)
48+
self.assertNotEqual(a, c)
49+
50+
with self.assertRaises(TypeError):
51+
a["d"] = 5
52+
53+
self.assertEqual(a, b)
54+
3755
def _test_overrides(self, c):
3856
c.override("debug_none", True)
3957
c.override("build_directory", "floober")
@@ -139,6 +157,19 @@ def test_conditional_in_file(self):
139157
self.assertEqual(c.prune_failed_graph, True)
140158
self.assertEqual(c.warn_all, True)
141159

160+
def test_conidition_nested(self):
161+
conf = os.path.join(self.config_path, "test_conditional.py")
162+
conf_dependee = os.path.join(self.config_path, "test_conditional_dependee.py")
163+
c = Config([conf, conf_dependee])
164+
self.assertEqual(c.dot_image_format, "hello")
165+
166+
def test_conidition_nested_inbeween(self):
167+
conf = os.path.join(self.config_path, "test_conditional.py")
168+
conf_middle = os.path.join(self.config_path, "test2.py")
169+
conf_dependee = os.path.join(self.config_path, "test_conditional_dependee.py")
170+
c = Config([conf, conf_middle, conf_dependee])
171+
self.assertEqual(c.dot_image_format, "hello")
172+
142173
def test_1(self):
143174
"""Test just the root config file."""
144175

src/rez/utils/data_utils.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Utilities related to managing data types.
33
"""
4+
from collections import Mapping
45
from rez.exceptions import ConditionalConfigurationError
56
from rez.vendor.schema.schema import Schema, Optional
67
from rez.vendor.six import six
@@ -683,7 +684,10 @@ def __new__(cls, base, frame, options, default=ConditionalConfigurationError):
683684
# a global config.
684685
platform_map = frame.f_locals.get(
685686
"platform_map",
686-
None
687+
frame.f_locals.get(
688+
"__fallback_platform_map",
689+
None
690+
)
687691
)
688692

689693
return base(options, default, platform_map=platform_map)
@@ -711,6 +715,41 @@ def __new__(cls, options, default=ConditionalConfigurationError):
711715
default)
712716

713717

718+
class HashableDict(Mapping):
719+
"""
720+
Immutable Hashable dict
721+
722+
Hash is based on key and value.
723+
It supports nested dict-like values.
724+
It does ignore any order of the items.
725+
726+
Could be replaced in future with:
727+
https://www.python.org/dev/peps/pep-0603/#why-frozenmap-and-not-frozendict
728+
"""
729+
730+
def __init__(self, *args, **kwargs):
731+
self._d = dict(*args, **kwargs)
732+
self._hash = None
733+
734+
for k, v in self._d.items():
735+
if isinstance(v, dict):
736+
self._d[k] = HashableDict(v)
737+
738+
def __iter__(self):
739+
return iter(self._d)
740+
741+
def __len__(self):
742+
return len(self._d)
743+
744+
def __getitem__(self, key):
745+
return self._d[key]
746+
747+
def __hash__(self):
748+
return hash(
749+
(frozenset(six.iteritems(self._d)), frozenset(six.itervalues(self._d)))
750+
)
751+
752+
714753
# Copyright 2013-2016 Allan Johns.
715754
#
716755
# This library is free software: you can redistribute it and/or

0 commit comments

Comments
 (0)