Source code for python.external_config.file_cache

# Copyright (c) 2018 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.
import os
import cPickle as pickle
import hashlib
import sgtk

logger = sgtk.platform.get_logger(__name__)

# if this key is found in the cache, a folder
# will this name will be generated as part of
# the cache path
FOLDER_PREFIX_KEY = "prefix"

[docs]def load_cache(identifier_dict): """ Loads a cache from disk given a dictionary of identifiers, e.g. ``{shot: 123, project: 345}`` etc. A hash value will be computed based on the identifier and used to find and load a cached payload. :param dict identifier_dict: Dictionary of identifying data. :returns: Cached data as generated by :meth:`write_cache`. """ cache_path = get_cache_path(identifier_dict) return load_cache_file(cache_path)
[docs]@sgtk.LogManager.log_timing def load_cache_file(cache_path): """ Loads a cache from disk given a file path generated by :meth:`get_cache_path`. If the file is not found, ``None`` is returned. :param str cache_path: Path to a cache file on disk. :returns: Cached data as generated by :meth:`write_cache` or ``None`` if file is not found. """ logger.debug("Loading from disk: %s" % cache_path) content = None if os.path.exists(cache_path): try: with open(cache_path, "rb") as fh: content = pickle.load(fh) except Exception as e: logger.debug("Cache '%s' not valid - ignoring. Details: %s" % (cache_path, e), exec_info=True) else: logger.debug("No cache found on disk.") return content
[docs]@sgtk.LogManager.log_timing def delete_cache(identifier_dict): """ Deletes a cache given its identifier. If no cache file exists, nothing is executed. :param dict identifier_dict: Dictionary of identifying data. """ cache_path = get_cache_path(identifier_dict) logger.debug("Deleting from disk: %s" % cache_path) sgtk.util.filesystem.safe_delete_file(cache_path)
[docs]def write_cache(identifier_dict, data): """ Writes cache data to disk given a dictionary of identifiers, e.g. ``{shot: 123, project: 345}`` etc. A hash value will be computed based on the identifier and used to determine the location for where the cache file will be saved :param dict identifier_dict: Dictionary of identifying data. :param data: Data to save. """ cache_path = get_cache_path(identifier_dict) return write_cache_file(cache_path, data)
[docs]@sgtk.LogManager.log_timing @sgtk.util.filesystem.with_cleared_umask def write_cache_file(path, data): """ Writes a cache to disk given a file path generated by :meth:`get_cache_path`. :param str path: Path to a cache file on disk. :param data: Data to save. """ logger.debug("Saving cache to disk: %s" % path) # try to create the cache folder with as open permissions as possible cache_dir = os.path.dirname(path) sgtk.util.filesystem.ensure_folder_exists(cache_dir) try: with open(path, "wb") as fh: pickle.dump(data, fh) # and ensure the cache file has got open permissions os.chmod(path, 0666) except Exception as e: logger.debug("Could not write '%s'. Details: %s" % (path, e), exec_info=True) else: logger.debug("Completed save of %s. Size %s bytes" % (path, os.path.getsize(path)))
[docs]def get_cache_path(identifier_dict): """ Create a file name given a dictionary of identifiers, e.g. ``{shot: 123, project: 345}`` etc. A hash value will be computed based on the identifier and used to determine the path. The current user will be added to the hash in order to make it user-centric. If the hash key 'prefix' is detected, this will be added to the path as a parent folder to the cache file. This provides a simple way to organize different caches into different folders. :param dict identifier_dict: Dictionary of identifying data. :retuns: path on disk, relative to the current bundle's cache location. """ params_hash = hashlib.md5() for (k, v) in identifier_dict.iteritems(): params_hash.update(str(k)) params_hash.update(str(v)) # add current user to hash user = sgtk.get_authenticated_user() if user and user.login: params_hash.update(user.login) cache_location = sgtk.platform.current_bundle().cache_location if FOLDER_PREFIX_KEY in identifier_dict: # if FOLDER_PREFIX_KEY is found in the hash, # this will be added as a folder to the path data_cache_path = os.path.join( cache_location, "external_cfg", identifier_dict[FOLDER_PREFIX_KEY], "%s.pkl" % params_hash.hexdigest() ) else: data_cache_path = os.path.join( cache_location, "external_cfg", "%s.pkl" % params_hash.hexdigest() ) logger.debug( "Resolved cache path for %s to %s" % (identifier_dict, data_cache_path) ) return data_cache_path