docs: def find_and_modify(self, query={}, update=None,
                          upsert=False, sort=None, full_response=False,
                          manipulate=False, **kwargs):
          """Update and return an object.
  
          **DEPRECATED** - Use :meth:`find_one_and_delete`,
          :meth:`find_one_and_replace`, or :meth:`find_one_and_update` instead.
          """
          warnings.warn("find_and_modify is deprecated, use find_one_and_delete"
                        ", find_one_and_replace, or find_one_and_update instead",
                        DeprecationWarning, stacklevel=2)
  
          if not update and not kwargs.get('remove', None):
              raise ValueError("Must either update or remove")
  
          if update and kwargs.get('remove', None):
              raise ValueError("Can't do both update and remove")
  
          # No need to include empty args
          if query:
              kwargs['query'] = query
          if update:
              kwargs['update'] = update
          if upsert:
              kwargs['upsert'] = upsert
          if sort:
              # Accept a list of tuples to match Cursor's sort parameter.
              if isinstance(sort, list):
                  kwargs['sort'] = helpers._index_document(sort)
              # Accept OrderedDict, SON, and dict with len == 1 so we
              # don't break existing code already using find_and_modify.
              elif (isinstance(sort, _ORDERED_TYPES) or
                    isinstance(sort, dict) and len(sort) == 1):
                  warnings.warn("Passing mapping types for `sort` is deprecated,"
                                " use a list of (key, direction) pairs instead",
                                DeprecationWarning, stacklevel=2)
                  kwargs['sort'] = sort
              else:
                  raise TypeError("sort must be a list of (key, direction) "
                                  "pairs, a dict of len 1, or an instance of "
                                  "SON or OrderedDict")
  
          fields = kwargs.pop("fields", None)
          if fields is not None:
              kwargs["fields"] = helpers._fields_list_to_dict(fields, "fields")
  
          collation = validate_collation_or_none(kwargs.pop('collation', None))
  
          cmd = SON([("findAndModify", self.__name)])
          cmd.update(kwargs)
          with self._socket_for_writes() as sock_info:
              if sock_info.max_wire_version >= 4 and 'writeConcern' not in cmd:
                  wc_doc = self.write_concern.document
                  if wc_doc:
                      cmd['writeConcern'] = wc_doc
              out = self._command(sock_info, cmd,
                                  read_preference=ReadPreference.PRIMARY,
                                  allowable_errors=[_NO_OBJ_ERROR],
                                  collation=collation)
              _check_write_command_response([(0, out)])
  
          if not out['ok']:
              if out["errmsg"] == _NO_OBJ_ERROR:
                  return None
              else:
                  # Should never get here b/c of allowable_errors
                  raise ValueError("Unexpected Error: %s" % (out,))
  
          if full_response:
              return out
          else:
              document = out.get('value')
              if manipulate:
                  document = self.__database._fix_outgoing(document, self)
              return document