Skip to content

Commit dee07cc

Browse files
committed
Made the dicts being serialized ordered.
Signed-off-by: KOLANICH <[email protected]>
1 parent 6b03ef4 commit dee07cc

File tree

1 file changed

+69
-43
lines changed

1 file changed

+69
-43
lines changed

tuf/api/metadata.py

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@
4343
List,
4444
Mapping,
4545
Optional,
46+
OrderedDict as OrderedDictT,
4647
Tuple,
4748
Type,
4849
TypeVar,
4950
Union,
5051
cast,
5152
)
53+
from collections import OrderedDict
5254

5355
from securesystemslib import exceptions as sslib_exceptions
5456
from securesystemslib import hash as sslib_hash
@@ -293,16 +295,20 @@ def to_bytes(
293295

294296
return serializer.serialize(self)
295297

296-
def to_dict(self) -> Dict[str, Any]:
298+
def to_dict(self) -> OrderedDictT[str, Any]:
297299
"""Returns the dict representation of self."""
298300

299301
signatures = [sig.to_dict() for sig in self.signatures.values()]
300302

301-
return {
302-
"signatures": signatures,
303-
"signed": self.signed.to_dict(),
304-
**self.unrecognized_fields,
305-
}
303+
return OrderedDict(
304+
(
305+
("signatures", signatures),
306+
("signed", self.signed.to_dict()),
307+
)
308+
+ tuple(
309+
sorted(self.unrecognized_fields.items(), key=lambda x: x[0])
310+
)
311+
)
306312

307313
def to_file(
308314
self,
@@ -582,19 +588,21 @@ def _common_fields_from_dict(
582588

583589
return version, spec_version, expires
584590

585-
def _common_fields_to_dict(self) -> Dict[str, Any]:
591+
def _common_fields_to_dict(self) -> OrderedDictT[str, Any]:
586592
"""Returns dict representation of common fields of ``Signed`` instances.
587593
588594
See ``{Root, Timestamp, Snapshot, Targets}.to_dict`` methods for usage.
589595
590596
"""
591-
return {
592-
"_type": self._type,
593-
"version": self.version,
594-
"spec_version": self.spec_version,
595-
"expires": self.expires.isoformat() + "Z",
596-
**self.unrecognized_fields,
597-
}
597+
return OrderedDict(
598+
{
599+
"_type": self._type,
600+
"version": self.version,
601+
"spec_version": self.spec_version,
602+
"expires": self.expires.isoformat() + "Z",
603+
**self.unrecognized_fields,
604+
}
605+
)
598606

599607
def is_expired(self, reference_time: Optional[datetime] = None) -> bool:
600608
"""Checks metadata expiration against a reference time.
@@ -682,14 +690,16 @@ def from_dict(cls, keyid: str, key_dict: Dict[str, Any]) -> "Key":
682690
# All fields left in the key_dict are unrecognized.
683691
return cls(keyid, keytype, scheme, keyval, key_dict)
684692

685-
def to_dict(self) -> Dict[str, Any]:
693+
def to_dict(self) -> OrderedDictT[str, Any]:
686694
"""Returns the dictionary representation of self."""
687-
return {
688-
"keytype": self.keytype,
689-
"scheme": self.scheme,
690-
"keyval": self.keyval,
691-
**self.unrecognized_fields,
692-
}
695+
return OrderedDict(
696+
{
697+
"keytype": self.keytype,
698+
"scheme": self.scheme,
699+
"keyval": self.keyval,
700+
**self.unrecognized_fields,
701+
}
702+
)
693703

694704
def to_securesystemslib_key(self) -> Dict[str, Any]:
695705
"""Returns a ``Securesystemslib`` compatible representation of self."""
@@ -840,13 +850,17 @@ def from_dict(cls, role_dict: Dict[str, Any]) -> "Role":
840850
# All fields left in the role_dict are unrecognized.
841851
return cls(keyids, threshold, role_dict)
842852

843-
def to_dict(self) -> Dict[str, Any]:
853+
def to_dict(self) -> OrderedDictT[str, Any]:
844854
"""Returns the dictionary representation of self."""
845-
return {
846-
"keyids": self.keyids,
847-
"threshold": self.threshold,
848-
**self.unrecognized_fields,
849-
}
855+
return OrderedDict(
856+
(
857+
("keyids", self.keyids),
858+
("threshold", self.threshold),
859+
)
860+
+ tuple(
861+
sorted(self.unrecognized_fields.items(), key=lambda x: x[0])
862+
)
863+
)
850864

851865

852866
class Root(Signed):
@@ -927,12 +941,15 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Root":
927941
# All fields left in the signed_dict are unrecognized.
928942
return cls(*common_args, keys, roles, consistent_snapshot, signed_dict)
929943

930-
def to_dict(self) -> Dict[str, Any]:
944+
def to_dict(self) -> OrderedDictT[str, Any]:
931945
"""Returns the dict representation of self."""
932946
root_dict = self._common_fields_to_dict()
933-
keys = {keyid: key.to_dict() for (keyid, key) in self.keys.items()}
934-
roles = {}
935-
for role_name, role in self.roles.items():
947+
keys = OrderedDict(
948+
(keyid, key.to_dict())
949+
for (keyid, key) in sorted(self.keys.items(), key=lambda x: x[0])
950+
)
951+
roles = OrderedDict()
952+
for role_name, role in sorted(self.roles.items(), key=lambda x: x[0]):
936953
roles[role_name] = role.to_dict()
937954
if self.consistent_snapshot is not None:
938955
root_dict["consistent_snapshot"] = self.consistent_snapshot
@@ -1274,11 +1291,13 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Snapshot":
12741291
# All fields left in the snapshot_dict are unrecognized.
12751292
return cls(*common_args, meta, signed_dict)
12761293

1277-
def to_dict(self) -> Dict[str, Any]:
1294+
def to_dict(self) -> OrderedDictT[str, Any]:
12781295
"""Returns the dict representation of self."""
12791296
snapshot_dict = self._common_fields_to_dict()
1280-
meta_dict = {}
1281-
for meta_path, meta_info in self.meta.items():
1297+
meta_dict = OrderedDict()
1298+
for meta_path, meta_info in sorted(
1299+
self.meta.items(), key=lambda x: x[0]
1300+
):
12821301
meta_dict[meta_path] = meta_info.to_dict()
12831302

12841303
snapshot_dict["meta"] = meta_dict
@@ -1695,13 +1714,18 @@ def from_dict(cls, delegations_dict: Dict[str, Any]) -> "Delegations":
16951714
# All fields left in the delegations_dict are unrecognized.
16961715
return cls(keys_res, roles_res, succinct_roles_info, delegations_dict)
16971716

1698-
def to_dict(self) -> Dict[str, Any]:
1717+
def to_dict(self) -> OrderedDictT[str, Any]:
16991718
"""Returns the dict representation of self."""
1700-
keys = {keyid: key.to_dict() for keyid, key in self.keys.items()}
1701-
res_dict: Dict[str, Any] = {
1702-
"keys": keys,
1703-
**self.unrecognized_fields,
1704-
}
1719+
keys = OrderedDict(
1720+
(keyid, key.to_dict())
1721+
for keyid, key in sorted(self.keys.items(), key=lambda x: x[0])
1722+
)
1723+
res_dict: Dict[str, Any] = OrderedDict(
1724+
{
1725+
"keys": keys,
1726+
**self.unrecognized_fields,
1727+
}
1728+
)
17051729
if self.roles is not None:
17061730
roles = [role_obj.to_dict() for role_obj in self.roles.values()]
17071731
res_dict["roles"] = roles
@@ -1967,11 +1991,13 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Targets":
19671991
# All fields left in the targets_dict are unrecognized.
19681992
return cls(*common_args, res_targets, delegations, signed_dict)
19691993

1970-
def to_dict(self) -> Dict[str, Any]:
1994+
def to_dict(self) -> OrderedDictT[str, Any]:
19711995
"""Returns the dict representation of self."""
19721996
targets_dict = self._common_fields_to_dict()
1973-
targets = {}
1974-
for target_path, target_file_obj in self.targets.items():
1997+
targets = OrderedDict()
1998+
for target_path, target_file_obj in sorted(
1999+
self.targets.items(), key=lambda x: x[0]
2000+
):
19752001
targets[target_path] = target_file_obj.to_dict()
19762002
targets_dict[_TARGETS] = targets
19772003
if self.delegations is not None:

0 commit comments

Comments
 (0)