Skip to content

Commit

Permalink
Metadata API: Fix type hints
Browse files Browse the repository at this point in the history
* Define missing argument type hints
* Stop using Mapping where we actually mean Dict:
  Mapping means "we only need a read-only dict" and most of the
  time this is not really the case.
* Use List, not list (latter only works from Python 3.9)
* Update Metadata.signatures documentation

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>

List not list

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
  • Loading branch information
Jussi Kukkonen committed May 7, 2021
1 parent aa83e9f commit 142ee94
Showing 1 changed file with 34 additions and 44 deletions.
78 changes: 34 additions & 44 deletions tuf/api/metadata.py
Expand Up @@ -17,7 +17,7 @@
"""
import tempfile
from datetime import datetime, timedelta
from typing import Any, Dict, Mapping, Optional
from typing import Any, Dict, List, Mapping, Optional

from securesystemslib.keys import verify_signature
from securesystemslib.signer import Signature, Signer
Expand All @@ -42,25 +42,17 @@ class Metadata:
signed: A subclass of Signed, which has the actual metadata payload,
i.e. one of Targets, Snapshot, Timestamp or Root.
signatures: A list of signatures over the canonical representation of
the value of the signed attribute::
[
{
'keyid': '<SIGNING KEY KEYID>',
'sig':' '<SIGNATURE HEX REPRESENTATION>'
},
...
]
signatures: A list of Securesystemslib Signature objects, each signing
the canonical serialized representation of 'signed'.
"""

def __init__(self, signed: "Signed", signatures: list) -> None:
def __init__(self, signed: "Signed", signatures: List[Signature]) -> None:
self.signed = signed
self.signatures = signatures

@classmethod
def from_dict(cls, metadata: Mapping[str, Any]) -> "Metadata":
def from_dict(cls, metadata: Dict[str, Any]) -> "Metadata":
"""Creates Metadata object from its dict representation.
Arguments:
Expand All @@ -71,7 +63,7 @@ def from_dict(cls, metadata: Mapping[str, Any]) -> "Metadata":
ValueError: The metadata has an unrecognized signed._type field.
Side Effect:
Destroys the metadata Mapping passed by reference.
Destroys the metadata dict passed by reference.
Returns:
A TUF Metadata object.
Expand Down Expand Up @@ -339,7 +331,7 @@ def __init__(
version: int,
spec_version: str,
expires: datetime,
unrecognized_fields: Optional[Mapping[str, Any]] = None,
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
self.spec_version = spec_version
self.expires = expires
Expand All @@ -351,7 +343,7 @@ def __init__(
self.unrecognized_fields = unrecognized_fields or {}

@classmethod
def _common_fields_from_dict(cls, signed_dict: Mapping[str, Any]) -> list:
def _common_fields_from_dict(cls, signed_dict: Dict[str, Any]) -> List[Any]:
"""Returns common fields of 'Signed' instances from the passed dict
representation, and returns an ordered list to be passed as leading
positional arguments to a subclass constructor.
Expand Down Expand Up @@ -429,8 +421,8 @@ def __init__(
self,
keytype: str,
scheme: str,
keyval: Mapping[str, str],
unrecognized_fields: Optional[Mapping[str, Any]] = None,
keyval: Dict[str, str],
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
if not keyval.get("public"):
raise ValueError("keyval doesn't follow the specification format!")
Expand All @@ -440,15 +432,15 @@ def __init__(
self.unrecognized_fields = unrecognized_fields or {}

@classmethod
def from_dict(cls, key_dict: Mapping[str, Any]) -> "Key":
def from_dict(cls, key_dict: Dict[str, Any]) -> "Key":
"""Creates Key object from its dict representation."""
keytype = key_dict.pop("keytype")
scheme = key_dict.pop("scheme")
keyval = key_dict.pop("keyval")
# All fields left in the key_dict are unrecognized.
return cls(keytype, scheme, keyval, key_dict)

def to_dict(self) -> Dict:
def to_dict(self) -> Dict[str, Any]:
"""Returns the dictionary representation of self."""
return {
"keytype": self.keytype,
Expand All @@ -472,9 +464,9 @@ class Role:

def __init__(
self,
keyids: list,
keyids: List[str],
threshold: int,
unrecognized_fields: Optional[Mapping[str, Any]] = None,
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
keyids_set = set(keyids)
if len(keyids_set) != len(keyids):
Expand All @@ -487,14 +479,14 @@ def __init__(
self.unrecognized_fields = unrecognized_fields or {}

@classmethod
def from_dict(cls, role_dict: Mapping[str, Any]) -> "Role":
def from_dict(cls, role_dict: Dict[str, Any]) -> "Role":
"""Creates Role object from its dict representation."""
keyids = role_dict.pop("keyids")
threshold = role_dict.pop("threshold")
# All fields left in the role_dict are unrecognized.
return cls(keyids, threshold, role_dict)

def to_dict(self) -> Dict:
def to_dict(self) -> Dict[str, Any]:
"""Returns the dictionary representation of self."""
return {
"keyids": list(self.keyids),
Expand Down Expand Up @@ -536,17 +528,17 @@ def __init__(
spec_version: str,
expires: datetime,
consistent_snapshot: bool,
keys: Mapping[str, Key],
roles: Mapping[str, Role],
unrecognized_fields: Optional[Mapping[str, Any]] = None,
keys: Dict[str, Key],
roles: Dict[str, Role],
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(version, spec_version, expires, unrecognized_fields)
self.consistent_snapshot = consistent_snapshot
self.keys = keys
self.roles = roles

@classmethod
def from_dict(cls, root_dict: Mapping[str, Any]) -> "Root":
def from_dict(cls, root_dict: Dict[str, Any]) -> "Root":
"""Creates Root object from its dict representation."""
common_args = cls._common_fields_from_dict(root_dict)
consistent_snapshot = root_dict.pop("consistent_snapshot")
Expand Down Expand Up @@ -580,7 +572,7 @@ def to_dict(self) -> Dict[str, Any]:

# Update key for a role.
def add_key(
self, role: str, keyid: str, key_metadata: Mapping[str, Any]
self, role: str, keyid: str, key_metadata: Dict[str, Any]
) -> None:
"""Adds new key for 'role' and updates the key store."""
self.roles[role].keyids.add(keyid)
Expand Down Expand Up @@ -627,15 +619,15 @@ def __init__(
version: int,
spec_version: str,
expires: datetime,
meta: Mapping[str, Any],
unrecognized_fields: Optional[Mapping[str, Any]] = None,
meta: Dict[str, Any],
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(version, spec_version, expires, unrecognized_fields)
# TODO: Add class for meta
self.meta = meta

@classmethod
def from_dict(cls, timestamp_dict: Mapping[str, Any]) -> "Timestamp":
def from_dict(cls, timestamp_dict: Dict[str, Any]) -> "Timestamp":
"""Creates Timestamp object from its dict representation."""
common_args = cls._common_fields_from_dict(timestamp_dict)
meta = timestamp_dict.pop("meta")
Expand All @@ -649,9 +641,7 @@ def to_dict(self) -> Dict[str, Any]:
return timestamp_dict

# Modification.
def update(
self, version: int, length: int, hashes: Mapping[str, Any]
) -> None:
def update(self, version: int, length: int, hashes: Dict[str, Any]) -> None:
"""Assigns passed info about snapshot metadata to meta dict."""
self.meta["snapshot.json"] = {
"version": version,
Expand Down Expand Up @@ -694,15 +684,15 @@ def __init__(
version: int,
spec_version: str,
expires: datetime,
meta: Mapping[str, Any],
unrecognized_fields: Optional[Mapping[str, Any]] = None,
meta: Dict[str, Any],
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(version, spec_version, expires, unrecognized_fields)
# TODO: Add class for meta
self.meta = meta

@classmethod
def from_dict(cls, snapshot_dict: Mapping[str, Any]) -> "Snapshot":
def from_dict(cls, snapshot_dict: Dict[str, Any]) -> "Snapshot":
"""Creates Snapshot object from its dict representation."""
common_args = cls._common_fields_from_dict(snapshot_dict)
meta = snapshot_dict.pop("meta")
Expand All @@ -721,7 +711,7 @@ def update(
rolename: str,
version: int,
length: Optional[int] = None,
hashes: Optional[Mapping[str, Any]] = None,
hashes: Optional[Dict[str, Any]] = None,
) -> None:
"""Assigns passed (delegated) targets role info to meta dict."""
metadata_fn = f"{rolename}.json"
Expand Down Expand Up @@ -799,17 +789,17 @@ def __init__(
version: int,
spec_version: str,
expires: datetime,
targets: Mapping[str, Any],
delegations: Mapping[str, Any],
unrecognized_fields: Optional[Mapping[str, Any]] = None,
targets: Dict[str, Any],
delegations: Dict[str, Any],
unrecognized_fields: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(version, spec_version, expires, unrecognized_fields)
# TODO: Add class for meta
self.targets = targets
self.delegations = delegations

@classmethod
def from_dict(cls, targets_dict: Mapping[str, Any]) -> "Targets":
def from_dict(cls, targets_dict: Dict[str, Any]) -> "Targets":
"""Creates Targets object from its dict representation."""
common_args = cls._common_fields_from_dict(targets_dict)
targets = targets_dict.pop("targets")
Expand All @@ -829,6 +819,6 @@ def to_dict(self) -> Dict[str, Any]:
return targets_dict

# Modification.
def update(self, filename: str, fileinfo: Mapping[str, Any]) -> None:
def update(self, filename: str, fileinfo: Dict[str, Any]) -> None:
"""Assigns passed target file info to meta dict."""
self.targets[filename] = fileinfo

0 comments on commit 142ee94

Please sign in to comment.