This commit is contained in:
Todd Gamblin
2022-09-04 15:39:44 -07:00
parent e040940833
commit 3ccc744ac8
5 changed files with 72 additions and 24 deletions

View File

@@ -1111,3 +1111,32 @@ def __init__(self, callback):
def __get__(self, instance, owner):
return self.callback(owner)
def dict_list_to_tuple(dlist):
if isinstance(dlist, (list, tuple)):
return tuple(dict_list_to_tuple(elt) for elt in dlist)
elif isinstance(dlist, dict):
return tuple((key, dict_list_to_tuple(val)) for key, val in dlist.items())
else:
return dlist
class dict_list(list):
"""A list with an interface like an ordereddict that can be turned into a tuple."""
def __setitem__(self, key, value):
self.append((key, value))
def update(self, dict_like):
if isinstance(dict_like, (list, tuple)):
iterable = dict_like
else:
iterable = dict_like.items()
for i in iterable:
self.append(i)
def items(self):
for i in self:
yield i

View File

@@ -77,6 +77,7 @@
expansion when it is the first character in an id typed on the command line.
"""
import collections
import hashlib
import itertools
import operator
import os
@@ -521,15 +522,18 @@ def target_concrete(self):
"""True if the target is not a range or list."""
return ":" not in str(self.target) and "," not in str(self.target)
def to_dict(self):
d = syaml.syaml_dict(
[
def to_dict(self, dict_type=syaml.syaml_dict):
d = dict_type(
(
("platform", self.platform),
("platform_os", self.os),
("target", self.target.to_dict_or_value()),
]
(
"target",
self.target.to_dict_or_value(dict_type=dict_type) if self.target else None,
),
)
)
return syaml.syaml_dict([("arch", d)])
return dict_type([("arch", d)])
@staticmethod
def from_dict(d):
@@ -643,11 +647,11 @@ def _cmp_iter(self):
yield self.name
yield self.versions
def to_dict(self):
d = syaml.syaml_dict([("name", self.name)])
def to_dict(self, dict_type=syaml.syaml_dict):
d = dict_type([("name", self.name)])
d.update(self.versions.to_dict())
return syaml.syaml_dict([("compiler", d)])
return dict_type([("compiler", d)])
@staticmethod
def from_dict(d):
@@ -1853,7 +1857,13 @@ def process_hash_bit_prefix(self, bits):
"""Get the first <bits> bits of the DAG hash as an integer type."""
return spack.util.hash.base32_prefix_bits(self.process_hash(), bits)
def to_node_dict(self, hash=ht.dag_hash):
def dict_tuple(self, hash=ht.dag_hash):
# return lang.dict_list_to_tuple(self.to_node_dict())
dlist = self.to_node_dict(hash=hash, dict_type=lang.dict_list)
return lang.dict_list_to_tuple(dlist)
def to_node_dict(self, hash=ht.dag_hash, dict_type=syaml.syaml_dict):
"""Create a dictionary representing the state of this Spec.
``to_node_dict`` creates the content that is eventually hashed by
@@ -1905,30 +1915,30 @@ def to_node_dict(self, hash=ht.dag_hash):
Arguments:
hash (spack.hash_types.SpecHashDescriptor) type of hash to generate.
"""
d = syaml.syaml_dict()
d = dict_type()
d["name"] = self.name
if self.versions:
d.update(self.versions.to_dict())
d.update(self.versions.to_dict(dict_type=dict_type))
if self.architecture:
d.update(self.architecture.to_dict())
d.update(self.architecture.to_dict(dict_type=dict_type))
if self.compiler:
d.update(self.compiler.to_dict())
d.update(self.compiler.to_dict(dict_type=dict_type))
if self.namespace:
d["namespace"] = self.namespace
params = syaml.syaml_dict(sorted(v.yaml_entry() for _, v in self.variants.items()))
params = dict_type(sorted(v.yaml_entry() for _, v in self.variants.items()))
params.update(sorted(self.compiler_flags.items()))
if params:
d["parameters"] = params
if self.external:
d["external"] = syaml.syaml_dict(
d["external"] = dict_type(
[
("path", self.external_path),
("module", self.external_modules),
@@ -1968,12 +1978,12 @@ def to_node_dict(self, hash=ht.dag_hash):
for dspec in edges_for_name:
hash_tuple = (hash.name, dspec.spec._cached_hash(hash))
type_tuple = ("type", sorted(str(s) for s in dspec.deptypes))
deps_list.append(syaml.syaml_dict([name_tuple, hash_tuple, type_tuple]))
deps_list.append(dict_type([name_tuple, hash_tuple, type_tuple]))
d["dependencies"] = deps_list
# Name is included in case this is replacing a virtual.
if self._build_spec:
d["build_spec"] = syaml.syaml_dict(
d["build_spec"] = dict_type(
[("name", self.build_spec.name), (hash.name, self.build_spec._cached_hash(hash))]
)
return d
@@ -4784,6 +4794,15 @@ def clear_cached_hashes(self, ignore=()):
self._dunder_hash = None
def __hash__(self):
return hash(self.dict_tuple())
# node_dict = self.to_node_dict(hash=ht.dag_hash)
# json_text = sjson.dump(node_dict)
# sha = hashlib.sha1(json_text.encode("utf-8"))
# h = int.from_bytes(sha.digest()[:8], byteorder=sys.byteorder)
# print(h)
# return h
# If the spec is concrete, we leverage the process hash and just use
# a 64-bit prefix of it. The process hash has the advantage that it's
# computed once per concrete spec, and it's saved -- so if we read

View File

@@ -91,7 +91,7 @@ def from_dict_or_value(dict_or_value):
target_info = dict_or_value
return Target(target_info["name"])
def to_dict_or_value(self):
def to_dict_or_value(self, dict_type=syaml.syaml_dict):
"""Returns a dict or a value representing the current target.
String values are used to keep backward compatibility with generic
@@ -104,7 +104,7 @@ def to_dict_or_value(self):
if self.microarchitecture.vendor == "generic":
return str(self)
return syaml.syaml_dict(self.microarchitecture.to_dict(return_list_of_items=True))
return dict_type(self.microarchitecture.to_dict(return_list_of_items=True))
def __repr__(self):
cls_name = self.__class__.__name__

View File

@@ -277,7 +277,7 @@ def yaml_entry(self):
Returns:
tuple: (name, value_representation)
"""
return self.name, list(self.value)
return (self.name, tuple(self.value))
@property
def value(self):

View File

@@ -1011,12 +1011,12 @@ def overlaps(self, other):
o += 1
return False
def to_dict(self):
def to_dict(self, dict_type=syaml_dict):
"""Generate human-readable dict for YAML."""
if self.concrete:
return syaml_dict([("version", str(self[0]))])
return dict_type([("version", str(self[0]))])
else:
return syaml_dict([("versions", [str(v) for v in self])])
return dict_type([("versions", [str(v) for v in self])])
@staticmethod
def from_dict(dictionary):