| 2881 | return self._read_reply() |
| 2882 | |
| 2883 | def _read_reply(self): |
| 2884 | # Loop until we get a 'reply' or 'signal' from the client, |
| 2885 | # processing out-of-band 'complete' requests as they arrive. |
| 2886 | while True: |
| 2887 | if self._write_failed: |
| 2888 | raise EOFError |
| 2889 | |
| 2890 | msg = self._sockfile.readline() |
| 2891 | if not msg: |
| 2892 | raise EOFError |
| 2893 | |
| 2894 | try: |
| 2895 | payload = json.loads(msg) |
| 2896 | except json.JSONDecodeError: |
| 2897 | self.error(f"Disconnecting: client sent invalid JSON {msg!r}") |
| 2898 | raise EOFError |
| 2899 | |
| 2900 | match payload: |
| 2901 | case {"reply": str(reply)}: |
| 2902 | return reply |
| 2903 | case {"signal": str(signal)}: |
| 2904 | if signal == "INT": |
| 2905 | raise KeyboardInterrupt |
| 2906 | elif signal == "EOF": |
| 2907 | raise EOFError |
| 2908 | else: |
| 2909 | self.error( |
| 2910 | f"Received unrecognized signal: {signal}" |
| 2911 | ) |
| 2912 | # Our best hope of recovering is to pretend we |
| 2913 | # got an EOF to exit whatever mode we're in. |
| 2914 | raise EOFError |
| 2915 | case { |
| 2916 | "complete": { |
| 2917 | "text": str(text), |
| 2918 | "line": str(line), |
| 2919 | "begidx": int(begidx), |
| 2920 | "endidx": int(endidx), |
| 2921 | } |
| 2922 | }: |
| 2923 | items = self._complete_any(text, line, begidx, endidx) |
| 2924 | self._send(completions=items) |
| 2925 | continue |
| 2926 | # Valid JSON, but doesn't meet the schema. |
| 2927 | self.error(f"Ignoring invalid message from client: {msg}") |
| 2928 | |
| 2929 | def _complete_any(self, text, line, begidx, endidx): |
| 2930 | # If we're in 'interact' mode, we need to use the default completer |