Source code for pangea_api.remote_object


import os
import logging
import json
from time import time
from glob import glob
from requests.exceptions import HTTPError
from .file_system_cache import FileSystemCache

logger = logging.getLogger(__name__)  # Same name as calling module
logger.addHandler(logging.NullHandler())  # No output unless configured by calling program


class RemoteObjectError(Exception):
    pass


class RemoteObjectOverwriteError(RemoteObjectError):
    pass


[docs]class RemoteObject: optional_remote_fields = [] def __init__(self, *args, **kwargs): self._already_fetched = False self._modified = False self._deleted = False self.blob = None self.uuid = None self.cache = FileSystemCache() def __setattr__(self, key, val): if hasattr(self, 'deleted') and self._deleted: logger.error(f'Attribute cannot be set, RemoteObject has been deleted. {self}') raise RemoteObjectError('This object has been deleted.') super(RemoteObject, self).__setattr__(key, val) if key in self.remote_fields or key == self.parent_field: logger.debug(f'Setting RemoteObject modified. key "{key}"') super(RemoteObject, self).__setattr__('_modified', True)
[docs] def get_cached_blob(self): return self.cache.get_cached_blob(self)
[docs] def cache_blob(self, blob): return self.cache.cache_blob(self, blob)
[docs] def load_blob(self, blob): logger.debug(f'Loading blob. {blob}') if self._deleted: logger.error(f'Cannot load blob, RemoteObject has been deleted. {self}') raise RemoteObjectError('This object has been deleted.') for field in self.remote_fields: current = getattr(self, field, None) try: new = blob[field] except KeyError: if field not in self.optional_remote_fields: logger.error(f'Blob being loaded is missing key. {field}') raise KeyError(f'Key {field} is missing for object {self} (type {type(self)}) in blob: {blob}') new = None if current and current != new: is_overwrite = True if isinstance(current, dict) and isinstance(new, dict): append_only = True for k, v in current.items(): if (k not in new) or (new[k] != v): append_only = False break if append_only: is_overwrite = False if is_overwrite: logger.error(f'Loading blob would overwrite key. {field}') raise RemoteObjectOverwriteError(( f'Loading blob would overwrite field "{field}":\n\t' f'current: "{current}" (type: "{type(current)}")\n\t' f'new: "{new}" (type: "{type(new)}")' )) setattr(self, field, new)
[docs] def get(self): """Fetch the object from the server.""" if self._deleted: logger.error(f'Cannot GET blob, RemoteObject has been deleted. {self}') raise RemoteObjectError('This object has been deleted.') if not self._already_fetched: logger.debug(f'Fetching RemoteBlob. {self}') self._get() self._already_fetched = True self._modified = False else: logger.debug(f'RemoteObject has already been fetched. {self}') return self
[docs] def create(self): """Create this object on the server.""" if self._deleted: logger.error(f'Cannot create blob, RemoteObject has been deleted. {self}') raise RemoteObjectError('This object has been deleted.') if not self._already_fetched: logger.debug(f'Creating RemoteBlob. {self}') self._create() self._already_fetched = True self._modified = False else: logger.debug(f'RemoteObject has already been fetched. {self}') return self
[docs] def save(self): """Assuming the object exists on the server make the server-side object match the state of this object. """ if self._deleted: logger.error(f'Cannot save blob, RemoteObject has been deleted. {self}') raise RemoteObjectError('This object has been deleted.') if not self._already_fetched: msg = 'Attempting to SAVE an object which has not been fetched is disallowed.' raise RemoteObjectError(msg) if self._modified: logger.debug(f'Saving RemoteBlob. {self}') self.cache.clear_blob(self) self._save() self._modified = False else: logger.debug(f'RemoteBlob has not been modified. Nothing to save. {self}')
[docs] def idem(self): """Make the state of this object match the server.""" if self._deleted: raise RemoteObjectError('This object has been deleted.') if not self._already_fetched: try: self.get() except HTTPError: self.create() else: self.save() return self
[docs] def delete(self): logger.debug(f'Deleting RemoteBlob. {self}') self.knex.delete(self.nested_url()) self._already_fetched = False self._deleted = True