Source code for smc.base.structs

#  Licensed under the Apache License, Version 2.0 (the "License"); you may
#  not use this file except in compliance with the License. You may obtain
#  a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#  License for the specific language governing permissions and limitations
#  under the License.
"""
Common structures
"""
import collections
"""
be more tolerant for abc in older collections / older python 2.7
"""
try:
    collectionsAbc = collections.abc
except AttributeError:
    collectionsAbc = collections


[docs] class BaseIterable(object): """ A collections container that provides a pre-filled container. This container type is used when an element retrieval returns all of an elements data in a single query and will contain multiple values for the same serialized type. Elements can be retrieved from the container through iteration, slicing, or by using `get` and providing either the index or an attribute / value pair. If subclassing, it may be useful to override `get` to provide a restricted interface to common attributes to fetch. Examples:: >>> for status in engine.nodes[0].interface_status: ... status ... InterfaceStatus(aggregate_is_active=False, .... By index:: >>> engine.nodes[0].interface_status[1] Slicing:: >>> engine.nodes[0].interface_status[1:5:2] >>> engine.nodes[0].interface_status[::-1] Using get by index or attribute:: >>> engine.nodes[0].interface_status.get(1) >>> engine.nodes[0].interface_status.get(interface_id=2) :param iterable item: items for which to perform iteration. Can be another class with an __iter__ method also to chain iterators. """ def __init__(self, items): self.items = items def __getitem__(self, index): if not isinstance(index, (int, slice)): raise TypeError("Invalid index specified. Must be int or slice.") if isinstance(index, slice): return self.items[index.start: index.stop: index.step] else: return self.items[index]
[docs] def get(self, *args, **kwargs): """ Get an element from the iterable by an arg or kwarg. Args can be a single positional argument that is an index value to retrieve. If the specified index is out of range, None is returned. Otherwise use kwargs to provide a key/value. The key is expected to be a valid attribute of the iterated class. For example, to get an element that has a attribute name of 'foo', pass name='foo'. :raises ValueError: An argument was missing :return: the specified item, type is based on what is returned by this iterable, may be None """ if self: if args: index = args[0] if index <= len(self) - 1: return self[args[0]] return None elif kwargs: key, value = kwargs.popitem() for item in self.items: if getattr(item, key, None) == value: return item else: raise ValueError( "Missing argument. You must provide an " "arg or kwarg to fetch an element from the collection." )
def __iter__(self): return iter(self.items) def __bool__(self): return bool(self.items) __nonzero__ = __bool__ def __len__(self): return len(self.items) def __repr__(self): return "%s(items: %s)" % (self.__class__.__name__, len(self))
[docs] def count(self): """ Return the number of entries :rtype: int """ return len(self)
[docs] def all(self): """ Return the iterable as a list """ return list(self)
[docs] class SerializedIterable(BaseIterable): """ A pre-serialized list of elements. This is used when it's easier to provide a pre-serialized class as long as all elements are of the same type. :param iterable item: items for which to perform iteration. Can be another class with an __iter__ method also to chain iterators. :param model: optional class to serialize each iteration. """ def __init__(self, items, model): items = [model(**r) for r in items] super(SerializedIterable, self).__init__(items)
class NestedDict(collectionsAbc.MutableMapping): """ Generic dict structure that can be used to objectify complex json. This dict allows attribute access for data stored in the data dict by overridding getattr. """ def __init__(self, data=None, **kwargs): self.data = data if data else {} self.update(self.data, **kwargs) def __setitem__(self, key, value): self.data[key] = value def __getitem__(self, key): return self.data[key] def __delitem__(self, key): del self.data[key] def __iter__(self): return iter(self.data) def __len__(self): return len(self.data) def __getattr__(self, key): if key in self: return self[key] raise AttributeError("%r object has no attribute %r" % (self.__class__, key))