# -*- coding: utf-8 -*-
"""Fake (in-memory only) attribute container store for testing."""
import ast
import collections
import copy
from acstore import interface
from acstore.containers import interface as containers_interface
[docs]
class FakeAttributeContainerStore(interface.AttributeContainerStore):
"""Fake (in-memory only) attribute container store."""
[docs]
def __init__(self):
"""Initializes a fake (in-memory only) store."""
super(FakeAttributeContainerStore, self).__init__()
self._attribute_container_indexes = {}
self._attribute_containers = {}
self._is_open = False
def _RaiseIfNotReadable(self):
"""Raises if the store is not readable.
Raises:
OSError: if the store cannot be read from.
IOError: if the store cannot be read from.
"""
if not self._is_open:
raise IOError('Unable to read from closed storage writer.')
def _RaiseIfNotWritable(self):
"""Raises if the storage file is not writable.
Raises:
IOError: when the storage writer is closed.
OSError: when the storage writer is closed.
"""
if not self._is_open:
raise IOError('Unable to write to closed storage writer.')
def _WriteExistingAttributeContainer(self, container):
"""Writes an existing attribute container to the store.
Args:
container (AttributeContainer): attribute container.
Raises:
IOError: if an unsupported identifier is provided or if the attribute
container does not exist.
OSError: if an unsupported identifier is provided or if the attribute
container does not exist.
"""
identifier = container.GetIdentifier()
lookup_key = identifier.CopyToString()
containers = self._attribute_containers.get(container.CONTAINER_TYPE, None)
if containers is None or lookup_key not in containers:
raise IOError((
f'Missing attribute container: {container.CONTAINER_TYPE:s} with '
f'identifier: {lookup_key:s}'))
containers[lookup_key] = container
def _WriteNewAttributeContainer(self, container):
"""Writes a new attribute container to the store.
Args:
container (AttributeContainer): attribute container.
"""
containers = self._attribute_containers.get(container.CONTAINER_TYPE, None)
if containers is None:
containers = collections.OrderedDict()
self._attribute_containers[container.CONTAINER_TYPE] = containers
container_indexes = self._attribute_container_indexes.get(
container.CONTAINER_TYPE, None)
if container_indexes is None:
container_indexes = []
self._attribute_container_indexes[container.CONTAINER_TYPE] = (
container_indexes)
next_sequence_number = self._GetAttributeContainerNextSequenceNumber(
container.CONTAINER_TYPE)
identifier = containers_interface.AttributeContainerIdentifier(
name=container.CONTAINER_TYPE, sequence_number=next_sequence_number)
container.SetIdentifier(identifier)
lookup_key = identifier.CopyToString()
# Make sure the fake storage preserves the state of the attribute container.
containers[lookup_key] = copy.deepcopy(container)
container_indexes.append(lookup_key)
[docs]
def Close(self):
"""Closes the store.
Raises:
IOError: if the store is already closed.
OSError: if the store is already closed.
"""
if not self._is_open:
raise IOError('Store already closed.')
self._is_open = False
[docs]
def GetAttributeContainerByIdentifier(self, container_type, identifier):
"""Retrieves a specific type of container with a specific identifier.
Args:
container_type (str): container type.
identifier (AttributeContainerIdentifier): attribute container identifier.
Returns:
AttributeContainer: attribute container or None if not available.
"""
containers = self._attribute_containers.get(container_type, {})
lookup_key = identifier.CopyToString()
return containers.get(lookup_key, None)
[docs]
def GetAttributeContainerByIndex(self, container_type, index):
"""Retrieves a specific attribute container.
Args:
container_type (str): attribute container type.
index (int): attribute container index.
Returns:
AttributeContainer: attribute container or None if not available.
"""
containers = self._attribute_containers.get(container_type, {})
number_of_containers = len(containers)
if index < 0 or index >= number_of_containers:
return None
container_indexes = self._attribute_container_indexes.get(
container_type, None)
lookup_key = container_indexes[index]
return containers[lookup_key]
[docs]
def GetAttributeContainers(self, container_type, filter_expression=None):
"""Retrieves a specific type of attribute containers.
Args:
container_type (str): attribute container type.
filter_expression (Optional[str]): expression to filter the resulting
attribute containers by.
Yield:
AttributeContainer: attribute container.
"""
if filter_expression:
expression_ast = ast.parse(filter_expression, mode='eval')
filter_expression = compile(expression_ast, '<string>', mode='eval')
for attribute_container in self._attribute_containers.get(
container_type, {}).values():
if attribute_container.MatchesExpression(filter_expression):
yield attribute_container
[docs]
def GetNumberOfAttributeContainers(self, container_type):
"""Retrieves the number of a specific type of attribute containers.
Args:
container_type (str): attribute container type.
Returns:
int: the number of containers of a specified type.
"""
containers = self._attribute_containers.get(container_type, {})
return len(containers)
[docs]
def HasAttributeContainers(self, container_type):
"""Determines if a store contains a specific type of attribute container.
Args:
container_type (str): attribute container type.
Returns:
bool: True if the store contains the specified type of attribute
containers.
"""
containers = self._attribute_containers.get(container_type, {})
return bool(containers)
[docs]
def Open(self, **kwargs):
"""Opens the store.
Raises:
IOError: if the store is already opened.
OSError: if the store is already opened.
"""
if self._is_open:
raise IOError('Store already opened.')
self._is_open = True