docs: def save_doc(self, doc, doc_id=None, following_attachments=None):
          '''Imitate sending HTTP request to CouchDB server'''
  
          self.log("save_document called for doc: %r", doc)
  
          d = defer.Deferred()
  
          try:
              if not isinstance(doc, (str, unicode, )):
                  raise ValueError('Doc should be either str or unicode')
              doc = json.loads(doc)
              doc = self._set_id_and_revision(doc, doc_id)
  
              self.increase_stat('save_doc')
  
              self._documents[doc['_id']] = doc
              if doc['_id'] not in self._attachments:
                  self._attachments[doc['_id']] = dict()
              attachments = doc.get('_attachments', dict())
              for name in attachments:
                  if attachments[name].get('follows'):
                      if name not in following_attachments:
                          raise ValueError("Document id %s had attachment name"
                                           " %s marked with follows=True, but"
                                           " it was not passed to save_doc() "
                                           % (doc['_id'], name))
  
                      del attachments[name]['follows']
                      attachments[name]['stub'] = True
                      b = following_attachments[name].get_body()
                      self._attachments[doc['_id']][name] = b
  
                  elif name not in self._attachments[doc['_id']]:
                      raise ValueError("Document id %s body has attachment "
                                       "named %s "
                                       "but it is not in our cache " %
                                       (doc['_id'], name))
              for name in self._attachments[doc['_id']].keys():
                  if name not in attachments:
                      del self._attachments[doc['_id']][name]
                      self.log('Deleted attachment %s of the doc: %s because '
                               'its not in the _attachments key' %
                               (name, doc['_id']))
  
              self._expire_cache(doc['_id'])
  
              r = Response(ok=True, id=doc['_id'], rev=doc['_rev'])
              self._analize_changes(doc)
              d.callback(r)
          except (ConflictError, ValueError, ) as e:
              d.errback(e)
  
          return d