Source code for python.shotgun_model.data_handler_cache

# Copyright (c) 2016 Shotgun Software Inc.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.


from .util import compare_shotgun_data

[docs]class ShotgunDataHandlerCache(object): """ Low level convenience wrapper around a data handler cache. Contains a dictionary structure of simple objects suitable for fast serialization with pickle. Used in conjunction with the data handler. """ # internal constants for serialization performance (CACHE_BY_UID, CACHE_CHILDREN, UID, IS_LEAF, PARENT, FIELD, SG_DATA) = range(7) def __init__(self, raw_data=None): """ :param raw_data: raw data to initialize with. """ if raw_data: self._cache = raw_data else: # init clear cache self._cache = { self.CACHE_CHILDREN: {}, # hierarchy self.CACHE_BY_UID: {}, # uid-based lookup self.UID: None # the uid of the root is None } @property def raw_data(self): """ The raw dictionary data contained in the cache. """ return self._cache @property def size(self): """ The number of items in the cache """ return len(self._cache[self.CACHE_BY_UID]) @property def uids(self): """ All uids in unspecified order, as an iterator for scalability """ return self._cache[self.CACHE_BY_UID].iterkeys()
[docs] def get_child_uids(self, parent_uid): """ Returns all the child uids for the given parent Returned in unspecified order as an iterator for scalability :param parent_uid: Parent uid :returns: list of child uids """ if parent_uid is None: return self._cache[self.CACHE_CHILDREN].iterkeys() else: return self._cache[self.CACHE_BY_UID][parent_uid][self.CACHE_CHILDREN].iterkeys()
[docs] def item_exists(self, unique_id): """ Checks if an item exists in the cache :param unique_id: unique id for cache item :returns: True if item exists, false if not """ return unique_id in self._cache[self.CACHE_BY_UID]
[docs] def get_shotgun_data(self, unique_id): """ Optimization. Returns the shotgun data for the given uid. :param unique_id: unique id for cache item :returns: Associated Shotgun data dictionary """ return self._cache[self.CACHE_BY_UID][unique_id][self.SG_DATA]
[docs] def get_entry_by_uid(self, unique_id): """ Returns a :class:`ShotgunItemData` for a given unique id. :param unique_id: unique id for cache item :returns: :class:`ShotgunItemData` instance or None if not found. """ from .data_item import ShotgunItemData # local import to avoid cycles data = self._cache[self.CACHE_BY_UID].get(unique_id) return ShotgunItemData(data) if data else None
[docs] def get_all_items(self): """ Generator that returns all items in no particular order :returns: :class:`ShotgunItemData` instances """ for unique_id in self._cache[self.CACHE_BY_UID]: yield self.get_entry_by_uid(unique_id)
[docs] def get_children(self, parent_uid): """ Generator that returns all childen for the given item. :param parent_uid: unique id for cache item :returns: :class:`ShotgunItemData` instances """ from .data_item import ShotgunItemData # local import to avoid cycles if parent_uid is None: # this is the root cache_node = self._cache else: # resolve cache node from uid cache_node = self._cache[self.CACHE_BY_UID].get(parent_uid) if cache_node: for item in cache_node[self.CACHE_CHILDREN].itervalues(): data_item = ShotgunItemData(item) yield data_item
[docs] def add_item(self, parent_uid, sg_data, field_name, is_leaf, uid): """ Adds an item to the cache. Checks if the item already exists and if it does, performs an up to date check. If the data is different from the existing data, True is returned. :param parent_uid: parent unique id :param sg_data: Shotgun data dictionary :param field_name: optional name of associated shotgun field :param is_leaf: boolean to indicate if node is a child node :param uid: unique id for the item. :returns: True if the item was updated, False if not. """ if parent_uid is None: parent_node = self._cache else: parent_node = self._cache[self.CACHE_BY_UID][parent_uid] if uid in parent_node[self.CACHE_CHILDREN]: # node already exists. See if it differs existing_sg_data = parent_node[self.CACHE_CHILDREN][uid][self.SG_DATA] if compare_shotgun_data(existing_sg_data, sg_data): # data is the same return False else: # data has changed, so update the record parent_node[self.CACHE_CHILDREN][uid][self.SG_DATA] = sg_data parent_node[self.CACHE_CHILDREN][uid][self.FIELD] = field_name parent_node[self.CACHE_CHILDREN][uid][self.IS_LEAF] = is_leaf return True else: # brand new node item = { self.SG_DATA: sg_data, self.FIELD: field_name, self.IS_LEAF: is_leaf, self.UID: uid, self.PARENT: parent_node, self.CACHE_CHILDREN: {} } parent_node[self.CACHE_CHILDREN][uid] = item self._cache[self.CACHE_BY_UID][uid] = item return True
[docs] def take_item(self, unique_id): """ Remove and return the given unique id from the cache :param unique_id: unique id for cache item :returns: :class:`ShotgunItemData` instance or None if not found. """ item_data = self.get_entry_by_uid(unique_id) if item_data: # remove it item = self._cache[self.CACHE_BY_UID][unique_id] del self._cache[self.CACHE_BY_UID][unique_id] parent = item[self.PARENT] del parent[self.CACHE_CHILDREN][unique_id] return item_data