Source code for arxiv.canonical.manifest
"""Defines the structure of manifest records, used to store integrity info."""
import json
from enum import Enum
from typing import Optional, List, Dict, Any
from mypy_extensions import TypedDict
from .domain.version import EventType
[docs]class ManifestEntry(TypedDict, total=False):
"""Structure of a single entry in a manifest."""
key: str
checksum: Optional[str]
size_bytes: int
mime_type: str
number_of_events: int
number_of_events_by_type: Dict[EventType, int]
number_of_versions: int
[docs]class Manifest(TypedDict):
"""Structure of a manifest record."""
entries: List[ManifestEntry]
number_of_events: int
number_of_events_by_type: Dict[EventType, int]
number_of_versions: int
[docs]class ManifestEncoder(json.JSONEncoder):
"""JSON encoder for manifests."""
[docs] def unpack(self, obj: Any) -> Any:
"""Convert manifests and their members to native Python types."""
if isinstance(obj, Enum):
return obj.value
elif isinstance(obj, dict):
return {self.unpack(key): self.unpack(value)
for key, value in obj.items()}
elif isinstance(obj, list):
return [self.unpack(item) for item in obj]
return obj
[docs] def encode(self, obj: Any) -> Any:
"""Serialize manifest objects."""
return super(ManifestEncoder, self).encode(self.unpack(obj))
[docs]class ManifestDecoder(json.JSONDecoder):
"""JSON decoder for manifests."""
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Pass :func:`object_hook` to the base constructor."""
kwargs['object_hook'] = kwargs.get('object_hook', self.object_hook)
super(ManifestDecoder, self).__init__(*args, **kwargs)
[docs] def object_hook(self, obj: dict, **extra: Any) -> Any: # pylint: disable=method-hidden
"""Decode the manifest to domain types."""
if 'number_of_events_by_type' in obj:
obj['number_of_events_by_type'] = {
EventType(key): value
for key, value in obj['number_of_events_by_type'].items()
}
return obj
[docs]def make_empty_manifest() -> Manifest:
"""Generate a new empty manifest."""
return Manifest(entries=[],
number_of_events=0,
number_of_versions=0,
number_of_events_by_type={})
[docs]def checksum_from_manifest(manifest: Manifest, key: str) -> Optional[str]:
"""Retrieve a checksum for a key from a manifest."""
for entry in manifest['entries']:
if entry['key'] == key:
return entry['checksum']
raise KeyError(f'Not found: {key}')