Source code for aiida.repository.common
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved. #
# This file is part of the AiiDA code. #
# #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida-core #
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
"""Module with resources common to the repository."""
import enum
import typing
__all__ = ('FileType', 'File')
[docs]
class FileType(enum.Enum):
"""Enumeration to represent the type of a file object."""
DIRECTORY = 0
FILE = 1
[docs]
class File:
"""Data class representing a file object."""
[docs]
def __init__(
self,
name: str = '',
file_type: FileType = FileType.DIRECTORY,
key: typing.Union[str, None] = None,
objects: typing.Optional[typing.Dict[str, 'File']] = None,
) -> None:
"""Construct a new instance.
:param name: The final element of the file path
:param file_type: Identifies whether the File is a file or a directory
:param key: A key to map the file to its contents in the backend repository (file only)
:param objects: Mapping of child names to child Files (directory only)
:raises ValueError: If a key is defined for a directory,
or objects are defined for a file
"""
if not isinstance(name, str):
raise TypeError('name should be a string.')
if not isinstance(file_type, FileType):
raise TypeError('file_type should be an instance of `FileType`.')
if key is not None and not isinstance(key, str):
raise TypeError('key should be `None` or a string.')
if objects is not None and any(not isinstance(obj, self.__class__) for obj in objects.values()):
raise TypeError('objects should be `None` or a dictionary of `File` instances.')
if file_type == FileType.DIRECTORY and key is not None:
raise ValueError('an object of type `FileType.DIRECTORY` cannot define a key.')
if file_type == FileType.FILE and objects is not None:
raise ValueError('an object of type `FileType.FILE` cannot define any objects.')
self._name = name
self._file_type = file_type
self._key = key
self._objects = objects or {}
[docs]
@classmethod
def from_serialized(cls, serialized: dict, name='') -> 'File':
"""Construct a new instance from a serialized instance.
:param serialized: the serialized instance.
:return: the reconstructed file object.
"""
if 'k' in serialized:
file_type = FileType.FILE
key = serialized['k']
objects = None
else:
file_type = FileType.DIRECTORY
key = None
objects = {name: File.from_serialized(obj, name) for name, obj in serialized.get('o', {}).items()}
instance = cls.__new__(cls)
instance.__init__(name, file_type, key, objects) # type: ignore[misc]
return instance
[docs]
def serialize(self) -> dict:
"""Serialize the metadata into a JSON-serializable format.
.. note:: the serialization format is optimized to reduce the size in bytes.
:return: dictionary with the content metadata.
"""
if self.file_type == FileType.DIRECTORY:
if self.objects:
return {'o': {key: obj.serialize() for key, obj in self.objects.items()}}
return {}
return {'k': self.key}
@property
def name(self) -> str:
"""Return the name of the file object."""
return self._name
@property
def file_type(self) -> FileType:
"""Return the file type of the file object."""
return self._file_type
[docs]
def is_file(self) -> bool:
"""Return whether this instance is a file object."""
return self.file_type == FileType.FILE
[docs]
def is_dir(self) -> bool:
"""Return whether this instance is a directory object."""
return self.file_type == FileType.DIRECTORY
@property
def key(self) -> typing.Union[str, None]:
"""Return the key of the file object."""
return self._key
@property
def objects(self) -> typing.Dict[str, 'File']:
"""Return the objects of the file object."""
return self._objects
[docs]
def __eq__(self, other) -> bool:
"""Return whether this instance is equal to another file object instance."""
if not isinstance(other, self.__class__):
return False
equal_attributes = all(getattr(self, key) == getattr(other, key) for key in ['name', 'file_type', 'key'])
equal_object_keys = sorted(self.objects) == sorted(other.objects)
equal_objects = equal_object_keys and all(obj == other.objects[key] for key, obj in self.objects.items())
return equal_attributes and equal_objects
[docs]
def __repr__(self):
args = (self.name, self.file_type.value, self.key, self.objects.items())
return 'File<name={}, file_type={}, key={}, objects={}>'.format(*args)