(self, save=None)
return atomic_blobs_context()
Return a context manager to atomically save doc + blobs

        Usage::

            with doc.atomic_blobs():
                doc.put_attachment(...)
            # doc and blob are now saved

        Blobs saved inside the context manager will be deleted if an
        exception is raised inside the context body.

        :param save: A function to be called instead of `self.save()`
Return a context manager to atomically save doc + blobs
Return a context manager to atomically save doc + blobs
def atomic_blobs(self, save=None):
        """Return a context manager to atomically save doc + blobs

        Usage::

            with doc.atomic_blobs():
                doc.put_attachment(...)
            # doc and blob are now saved

        Blobs saved inside the context manager will be deleted if an
        exception is raised inside the context body.

        :param save: A function to be called instead of `self.save()`
        """
        @contextmanager
        def atomic_blobs_context():
            if self._id is None:
                self._id = uuid.uuid4().hex
            old_external_blobs = dict(self.external_blobs)
            if self._migrating_blobs_from_couch:
                if self._attachments:
                    old_attachments = dict(self._attachments)
                else:
                    old_attachments = None
            atomicity = self._atomic_blobs
            self._atomic_blobs = new_deleted = defaultdict(list)
            db = get_blob_db()
            success = False
            try:
                yield
                (self.save if save is None else save)()
                success = True
            except:
                typ, exc, tb = sys.exc_info()
                # delete new blobs that were not saved
                for name, meta in self.external_blobs.items():
                    old_meta = old_external_blobs.get(name)
                    if old_meta is None or meta.key != old_meta.key:
                        db.delete(key=meta.key)
                self.external_blobs = old_external_blobs
                if self._migrating_blobs_from_couch:
                    self._attachments = old_attachments
                six.reraise(typ, exc, tb)
            finally:
                self._atomic_blobs = atomicity
            if success:
                # delete replaced blobs
                deleted = set()
                blobs = self.blobs
                for name, meta in list(old_external_blobs.items()):
                    if name not in blobs or meta.key != blobs[name].key:
                        db.delete(key=meta.key)
                        deleted.add(meta.key)
                # delete newly created blobs that were overwritten or deleted
                for key in chain.from_iterable(new_deleted.values()):
                    if key not in deleted:
                        db.delete(key=key)
        return atomic_blobs_context()
def atomic_blobs ( self , save = None ) : @ contextmanager def atomic_blobs_context ( ) : if self . _id is None : self . _id = uuid . uuid4 ( ) . hex old_external_blobs = dict ( self . external_blobs ) if self . _migrating_blobs_from_couch : if self . _attachments : old_attachments = dict ( self . _attachments ) else : old_attachments = None atomicity = self . _atomic_blobs self . _atomic_blobs = new_deleted = defaultdict ( list ) db = get_blob_db ( ) success = False try : yield ( self . save if save is None else save ) ( ) success = True except : typ , exc , tb = sys . exc_info ( ) # delete new blobs that were not saved for name , meta in self . external_blobs . items ( ) : old_meta = old_external_blobs . get ( name ) if old_meta is None or meta . key != old_meta . key : db . delete ( key = meta . key ) self . external_blobs = old_external_blobs if self . _migrating_blobs_from_couch : self . _attachments = old_attachments six . reraise ( typ , exc , tb ) finally : self . _atomic_blobs = atomicity if success : # delete replaced blobs deleted = set ( ) blobs = self . blobs for name , meta in list ( old_external_blobs . items ( ) ) : if name not in blobs or meta . key != blobs [ name ] . key : db . delete ( key = meta . key ) deleted . add ( meta . key ) # delete newly created blobs that were overwritten or deleted for key in chain . from_iterable ( new_deleted . values ( ) ) : if key not in deleted : db . delete ( key = key ) return atomic_blobs_context ( )