def __send_message(self, operation):
        """Send a query or getmore operation and handles the response.

        If operation is ``None`` this is an exhaust cursor, which reads
        the next result batch off the exhaust socket instead of
        sending getMore messages to the server.

        Can raise ConnectionFailure.
        """
        client = self.__collection.database.client
        # OP_MSG is required to support exhaust cursors with encryption.
        if client._encrypter and self.__exhaust:
            raise InvalidOperation(
                "exhaust cursors do not support auto encryption")

        try:
            response = client._run_operation_with_response(
                operation, self._unpack_response, exhaust=self.__exhaust,
                address=self.__address)
        except OperationFailure:
            self.__killed = True

            # Make sure exhaust socket is returned immediately, if necessary.
            self.__die()

            # If this is a tailable cursor the error is likely
            # due to capped collection roll over. Setting
            # self.__killed to True ensures Cursor.alive will be
            # False. No need to re-raise.
            if self.__query_flags & _QUERY_OPTIONS["tailable_cursor"]:
                return
            raise
        except NotMasterError:
            # Don't send kill cursors to another server after a "not master"
            # error. It's completely pointless.
            self.__killed = True

            # Make sure exhaust socket is returned immediately, if necessary.
            self.__die()

            raise
        except ConnectionFailure:
            # Don't try to send kill cursors on another socket
            # or to another server. It can cause a _pinValue
            # assertion on some server releases if we get here
            # due to a socket timeout.
            self.__killed = True
            self.__die()
            raise
        except Exception:
            # Close the cursor
            self.__die()
            raise

        self.__address = response.address
        if self.__exhaust and not self.__exhaust_mgr:
            # 'response' is an ExhaustResponse.
            self.__exhaust_mgr = _SocketManager(response.socket_info,
                                                response.pool)

        cmd_name = operation.name
        docs = response.docs
        if response.from_command:
            if cmd_name != "explain":
                cursor = docs[0]['cursor']
                self.__id = cursor['id']
                if cmd_name == 'find':
                    documents = cursor['firstBatch']
                else:
                    documents = cursor['nextBatch']
                self.__data = deque(documents)
                self.__retrieved += len(documents)
            else:
                self.__id = 0
                self.__data = deque(docs)
                self.__retrieved += len(docs)
        else:
            self.__id = response.data.cursor_id
            self.__data = deque(docs)
            self.__retrieved += response.data.number_returned

        if self.__id == 0:
            self.__killed = True
            # Don't wait for garbage collection to call __del__, return the
            # socket and the session to the pool now.
            self.__die()

        if self.__limit and self.__id and self.__limit <= self.__retrieved:
            self.__die()
Send a query or getmore operation and handles the response.

        If operation is ``None`` this is an exhaust cursor, which reads
        the next result batch off the exhaust socket instead of
        sending getMore messages to the server.

        Can raise ConnectionFailure.
        
stackoverflow/venv/lib/python3.6/site-packages/pymongo/cursor.py