Example #1
0
    def get_answer(self) -> Tuple[Result, str]:
        """Read from 'out_q' and wait until a full response is received."""
        assert self.xml is not None
        data = []
        poll_sec = 1

        while True:
            # Abort if an error is printed to stderr, but ignore warnings.
            # NOTE: If `warnings_wf` is False because this version of Coq does
            # not follow the pattern expected by `partition_warnings` then
            # pretend everything is a warning and hope for the best.
            err = self.collect_err()
            if self.xml.warnings_wf and partition_warnings(err)[1] != "":
                return UNEXPECTED_ERR, err

            try:
                data.append(self.out_q.get(timeout=poll_sec))
            except Empty:
                continue
            xml = b"".join(data)
            if not self.xml.worth_parsing(xml):
                continue
            response = self.xml.raw_response(xml)

            if response is None:
                continue

            # Don't bother doing prettyxml if debugging isn't on
            if self.logger.isEnabledFor(logging.DEBUG):
                self.logger.debug(prettyxml(b"<response>" + xml + b"</response>"))
            return response, err
Example #2
0
    def get_answer(self) -> Result:
        """Read from 'out_q' and wait until a full response is received."""
        assert self.xml is not None
        data = []

        while True:
            data.append(self.out_q.get())
            xml = b"".join(data)
            if not self.xml.worth_parsing(xml):
                continue
            response = self.xml.raw_response(xml)

            if response is None:
                continue

            # Don't bother doing prettyxml if debugging isn't on
            if self.logger.isEnabledFor(logging.DEBUG):
                self.logger.debug(
                    prettyxml(b"<response>" + xml + b"</response>"))
            return response
Example #3
0
    def get_answer(self, res_ref):
        # type: (Ref) -> None
        """Read from 'out_q' and wait until a full response is received."""
        data = []

        while True:
            data.append(self.out_q.get())
            if not self.xml.worth_parsing(data[-1]):
                continue
            xml = b"".join(data)
            response = self.xml.raw_response(xml)

            if response is None:
                continue

            # Don't bother doing prettyxml if debugging isn't on
            if self.logger.isEnabledFor(logging.DEBUG):
                self.logger.debug(prettyxml(b"<response>" + xml + b"</response>"))
            res_ref.val = response
            # Notify the caller that Coqtop is done
            self.done_callback()
            break
Example #4
0
    def call(
        self,
        cmdtype_msg: Tuple[str, Optional[bytes]],
        timeout: Optional[int] = None,
    ) -> Tuple[Result, str]:
        """Send 'msg' to the Coqtop process and wait for the response."""
        assert self.xml is not None
        # Check if Coqtop has stopped
        if not self.running():
            raise CoqtopError("Coqtop is not running.")

        # Throw away any unread messages
        self.empty_out()

        # 'msg' can be None if a command does not exist for a particular
        # version and is being faked.
        # NOTE: It is important that the '_standardize' function being called
        # does not depend on the value it is passed since it is None
        cmd, msg = cmdtype_msg
        if msg is None:
            return self.xml.standardize(cmd, Ok(None)), self.collect_err()

        # Don't bother doing prettyxml if debugging isn't on
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug(prettyxml(msg))
        self.send_cmd(msg)

        with futures.ThreadPoolExecutor(1) as pool:
            try:
                timeout = timeout if timeout != 0 else None
                response = pool.submit(self.get_answer).result(timeout)
            except futures.TimeoutError:
                self.interrupt()
                response = TIMEOUT_ERR

        return self.xml.standardize(cmd, response), self.collect_err()
Example #5
0
    def call(
            self,
            cmdtype_msg,  # type: Tuple[Text, Optional[bytes]]
            timeout=None,  # type: Optional[int]
    ):
        # type: (...) -> Generator[Union[Ok, Err], bool, None]
        """Send 'msg' to the Coqtop process and wait for the response."""
        # Check if Coqtop has stopped
        if not self.running():
            raise CoqtopError("Coqtop is not running.")

        # Throw away any unread messages
        self.empty_out()

        cmd, msg = cmdtype_msg

        # 'msg' can be None if a command does not exist for a particular
        # version and is being faked.
        # N.B. It is important that the '_standardize' function being called
        # does not depend on the value it is passed since it is None
        if msg is None:
            self.done_callback()
            yield  # type: ignore[misc] # (see comment above start())
            yield self.xml.standardize(cmd, Ok(None))
            return

        # Don't bother doing prettyxml if debugging isn't on
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug(prettyxml(msg))
        self.send_cmd(msg)

        if timeout == 0:
            timeout = None

        # The got_response event tells the timeout_thread that get_answer()
        # returned normally, while timed_out will be set by timeout_thread if
        # time runs out without receiving a response
        got_response = threading.Event()
        timed_out = threading.Event()
        timeout_thread = threading.Thread(target=self.timeout_thread,
                                          args=(timeout, got_response,
                                                timed_out))
        timeout_thread.daemon = True

        # Start a thread to get Coqtop's response
        res_ref = Ref()
        answer_thread = threading.Thread(target=self.get_answer,
                                         args=(res_ref, ))
        answer_thread.daemon = True

        # Start threads and yield back to caller to wait for Coqtop to finish
        timeout_thread.start()
        answer_thread.start()
        stopped = yield  # type: ignore[misc] # (see comment above start())

        # Notify timeout_thread that a response is received and wait for
        # threads to finish
        got_response.set()
        timeout_thread.join()
        answer_thread.join()

        response = res_ref.val

        # Check for user interrupt or timeout
        if isinstance(response, Err):
            if stopped:
                response = STOPPED_ERR
            elif timed_out.is_set():
                response = TIMEOUT_ERR

        yield self.xml.standardize(cmd, response)