We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Check handling of str responses in Kite client signals
Sorry for taking so long to respond. I've included everything that I thought might be relevant. I think @metalogical has it right, however I it would be pretty difficult for me to convince the security guys at work to change anything. Would it be possible to change the error handling so it is able to continue after an error like this? Especially since I have explicitly disabled Kite and the software works fine if it encounters the error when already running. 

	2020-04-20 12:05:42,162 [DEBUG] [spyder.plugins.editor.plugin] -> Start completion server for C:\Users\[removed]\.spyder-py3\temp.py [Python]
	2020-04-20 12:05:42,162 [DEBUG] [spyder.plugins.editor.plugin] -> Python completion server is ready
	2020-04-20 12:05:42,164 [DEBUG] [spyder.plugins.editor.widgets.codeeditor] -> Completions services available for: C:\Users\[removed]\.spyder-py3\temp.py
	2020-04-20 12:05:42,164 [DEBUG] [spyder.plugins.editor.plugin] -> python completion server request: 'textDocument/didOpen'
	2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Completion plugin: Request 0 Got response from lsp
	2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Gather responses for textDocument/didOpen
	2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Completion plugin: Request 0 Got response from kite
	2020-04-20 12:05:42,166 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Set focus to: C:\Users\[removed]\.spyder-py3\temp.py
	2020-04-20 12:05:42,166 [DEBUG] [spyder.plugins.completion.fallback.actor] -> Got request id 0: textDocument/didOpen for file C:\Users\[removed]\.spyder-py3\temp.py
	2020-04-20 12:05:42,167 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Current changed: 0 - C:\Users\[removed]\.spyder-py3\temp.py
	2020-04-20 12:05:42,170 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Added thread <spyder.plugins.editor.widgets.editor.AnalysisThread object at 0x0000019B03720A68> to queue
	2020-04-20 12:05:42,189 [INFO] [spyder.app.mainwindow] -> Launching code completion client for Python...
	2020-04-20 12:05:42,203 [DEBUG] [spyder.plugins.completion.kite.client] -> Starting Kite HTTP session...
	2020-04-20 12:05:42,208 [DEBUG] [urllib3.connectionpool] -> Starting new HTTP connection (1): [vpn server name].[company name].com:80
	2020-04-20 12:05:42,512 [DEBUG] [urllib3.connectionpool] -> http://[vpn server name].[company name].com:80 "GET http://127.0.0.1:46624/clientapi/languages HTTP/1.1" 200 7277
	Traceback (most recent call last):
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\app\mainwindow.py", line 3718, in main
		mainwindow = run_spyder(app, options, args)
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\app\mainwindow.py", line 3559, in run_spyder
		main.setup()
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\app\mainwindow.py", line 960, in setup
		self.completions.start()
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\plugins\completion\plugin.py", line 292, in start
		client_info['plugin'].start()
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\plugins\completion\kite\plugin.py", line 144, in start
		self.client.start()
	  File "C:\Progra~1\Anaconda3\lib\site-packages\spyder\plugins\completion\kite\client.py", line 62, in start
		self.sig_client_started.emit(self.languages)
	TypeError: KiteClient.sig_client_started[list].emit(): argument 1 has unexpected type 'str'

_Originally posted by @nsluhrs in https://github.com/spyder-ide/spyder/issues/12357#issuecomment-616665440_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `spyder/plugins/completion/kite/client.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright © Spyder Project Contributors
4 # Licensed under the terms of the MIT License
5 # (see spyder/__init__.py for details)
6 
7 """Kite completions HTTP client."""
8 
9 # Standard library imports
10 import logging
11 try:
12     from urllib import quote  # Python 2
13 except ImportError:
14     from urllib.parse import quote  # Python 3
15 
16 # Third party imports
17 from qtpy.QtCore import QObject, QThread, Signal, QMutex
18 import requests
19 
20 # Local imports
21 from spyder.config.base import _
22 from spyder.plugins.completion.kite import KITE_ENDPOINTS, KITE_REQUEST_MAPPING
23 from spyder.plugins.completion.kite.decorators import class_register
24 from spyder.plugins.completion.kite.providers import KiteMethodProviderMixIn
25 from spyder.plugins.completion.kite.utils.status import (
26     status, check_if_kite_running)
27 from spyder.py3compat import (
28     ConnectionError, ConnectionRefusedError, TEXT_TYPES)
29 
30 
31 logger = logging.getLogger(__name__)
32 
33 
34 @class_register
35 class KiteClient(QObject, KiteMethodProviderMixIn):
36     sig_response_ready = Signal(int, dict)
37     sig_client_started = Signal(list)
38     sig_client_not_responding = Signal()
39     sig_perform_request = Signal(int, str, object)
40     sig_perform_status_request = Signal(str)
41     sig_status_response_ready = Signal((str,), (dict,))
42     sig_perform_onboarding_request = Signal()
43     sig_onboarding_response_ready = Signal(str)
44 
45     def __init__(self, parent, enable_code_snippets=True):
46         QObject.__init__(self, parent)
47         self.endpoint = None
48         self.requests = {}
49         self.languages = []
50         self.mutex = QMutex()
51         self.opened_files = {}
52         self.opened_files_status = {}
53         self.thread_started = False
54         self.enable_code_snippets = enable_code_snippets
55         self.thread = QThread()
56         self.moveToThread(self.thread)
57         self.thread.started.connect(self.started)
58         self.sig_perform_request.connect(self.perform_request)
59         self.sig_perform_status_request.connect(self.get_status)
60         self.sig_perform_onboarding_request.connect(self.get_onboarding_file)
61 
62     def start(self):
63         if not self.thread_started:
64             self.thread.start()
65         logger.debug('Starting Kite HTTP session...')
66         self.endpoint = requests.Session()
67         self.languages = self.get_languages()
68         self.sig_client_started.emit(self.languages)
69 
70     def started(self):
71         self.thread_started = True
72 
73     def stop(self):
74         if self.thread_started:
75             logger.debug('Closing Kite HTTP session...')
76             self.endpoint.close()
77             self.thread.quit()
78 
79     def get_languages(self):
80         verb, url = KITE_ENDPOINTS.LANGUAGES_ENDPOINT
81         success, response = self.perform_http_request(verb, url)
82         if response is None:
83             response = ['python']
84         return response
85 
86     def _get_onboarding_file(self):
87         """Perform a request to get kite's onboarding file."""
88         verb, url = KITE_ENDPOINTS.ONBOARDING_ENDPOINT
89         success, response = self.perform_http_request(verb, url)
90         return response
91 
92     def get_onboarding_file(self):
93         """Get onboarding file."""
94         onboarding_file = self._get_onboarding_file()
95         self.sig_onboarding_response_ready.emit(onboarding_file)
96 
97     def _get_status(self, filename):
98         """Perform a request to get kite status for a file."""
99         verb, url = KITE_ENDPOINTS.STATUS_ENDPOINT
100         if filename:
101             url_params = {'filename': filename}
102         else:
103             url_params = {'filetype': 'python'}
104         success, response = self.perform_http_request(
105             verb, url, url_params=url_params)
106         return success, response
107 
108     def get_status(self, filename):
109         """Get kite status for a given filename."""
110         success_status, kite_status = self._get_status(filename)
111         if not filename or kite_status is None:
112             kite_status = status()
113             self.sig_status_response_ready[str].emit(kite_status)
114         elif isinstance(kite_status, TEXT_TYPES):
115             if not success_status:
116                 status_str = status(extra_status=' with errors')
117                 long_str = _("<code>{error}</code><br><br>"
118                              "Note: If you are using a VPN, "
119                              "please don't route requests to "
120                              "localhost/127.0.0.1 with it").format(
121                                  error=kite_status)
122             else:
123                 status_str = status()
124                 long_str = kite_status
125             kite_status_dict = {
126                 'status': status_str,
127                 'short': status_str,
128                 'long': long_str}
129             self.sig_status_response_ready[dict].emit(kite_status_dict)
130         else:
131             self.sig_status_response_ready[dict].emit(kite_status)
132 
133     def perform_http_request(self, verb, url, url_params=None, params=None):
134         response = None
135         http_method = getattr(self.endpoint, verb)
136         try:
137             http_response = http_method(url, params=url_params, json=params)
138         except Exception as error:
139             return False, None
140         success = http_response.status_code == 200
141         if success:
142             try:
143                 response = http_response.json()
144             except Exception:
145                 response = http_response.text
146                 response = None if response == '' else response
147         return success, response
148 
149     def send(self, method, params, url_params):
150         response = None
151         if self.endpoint is not None and method in KITE_REQUEST_MAPPING:
152             http_verb, path = KITE_REQUEST_MAPPING[method]
153             encoded_url_params = {
154                 key: quote(value) if isinstance(value, TEXT_TYPES) else value
155                 for (key, value) in url_params.items()}
156             path = path.format(**encoded_url_params)
157             try:
158                 success, response = self.perform_http_request(
159                     http_verb, path, params=params)
160             except (ConnectionRefusedError, ConnectionError):
161                 return response
162         return response
163 
164     def perform_request(self, req_id, method, params):
165         response = None
166         if method in self.sender_registry:
167             logger.debug('Perform {0} request with id {1}'.format(
168                 method, req_id))
169             handler_name = self.sender_registry[method]
170             handler = getattr(self, handler_name)
171             response = handler(params)
172             if method in self.handler_registry:
173                 converter_name = self.handler_registry[method]
174                 converter = getattr(self, converter_name)
175                 if response is not None:
176                     response = converter(response)
177         self.sig_response_ready.emit(req_id, response or {})
178
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/spyder/plugins/completion/kite/client.py b/spyder/plugins/completion/kite/client.py
--- a/spyder/plugins/completion/kite/client.py
+++ b/spyder/plugins/completion/kite/client.py
@@ -79,7 +79,7 @@
     def get_languages(self):
         verb, url = KITE_ENDPOINTS.LANGUAGES_ENDPOINT
         success, response = self.perform_http_request(verb, url)
-        if response is None:
+        if response is None or isinstance(response, TEXT_TYPES):
             response = ['python']
         return response
 
@@ -112,16 +112,12 @@
             kite_status = status()
             self.sig_status_response_ready[str].emit(kite_status)
         elif isinstance(kite_status, TEXT_TYPES):
-            if not success_status:
-                status_str = status(extra_status=' with errors')
-                long_str = _("<code>{error}</code><br><br>"
-                             "Note: If you are using a VPN, "
-                             "please don't route requests to "
-                             "localhost/127.0.0.1 with it").format(
-                                 error=kite_status)
-            else:
-                status_str = status()
-                long_str = kite_status
+            status_str = status(extra_status=' with errors')
+            long_str = _("<code>{error}</code><br><br>"
+                         "Note: If you are using a VPN, "
+                         "please don't route requests to "
+                         "localhost/127.0.0.1 with it").format(
+                             error=kite_status)
             kite_status_dict = {
                 'status': status_str,
                 'short': status_str,

{"golden_diff": "diff --git a/spyder/plugins/completion/kite/client.py b/spyder/plugins/completion/kite/client.py\n--- a/spyder/plugins/completion/kite/client.py\n+++ b/spyder/plugins/completion/kite/client.py\n@@ -79,7 +79,7 @@\n     def get_languages(self):\n         verb, url = KITE_ENDPOINTS.LANGUAGES_ENDPOINT\n         success, response = self.perform_http_request(verb, url)\n-        if response is None:\n+        if response is None or isinstance(response, TEXT_TYPES):\n             response = ['python']\n         return response\n \n@@ -112,16 +112,12 @@\n             kite_status = status()\n             self.sig_status_response_ready[str].emit(kite_status)\n         elif isinstance(kite_status, TEXT_TYPES):\n-            if not success_status:\n-                status_str = status(extra_status=' with errors')\n-                long_str = _(\"<code>{error}</code><br><br>\"\n-                             \"Note: If you are using a VPN, \"\n-                             \"please don't route requests to \"\n-                             \"localhost/127.0.0.1 with it\").format(\n-                                 error=kite_status)\n-            else:\n-                status_str = status()\n-                long_str = kite_status\n+            status_str = status(extra_status=' with errors')\n+            long_str = _(\"<code>{error}</code><br><br>\"\n+                         \"Note: If you are using a VPN, \"\n+                         \"please don't route requests to \"\n+                         \"localhost/127.0.0.1 with it\").format(\n+                             error=kite_status)\n             kite_status_dict = {\n                 'status': status_str,\n                 'short': status_str,\n", "issue": "Check handling of str responses in Kite client signals\nSorry for taking so long to respond. I've included everything that I thought might be relevant. I think @metalogical has it right, however I it would be pretty difficult for me to convince the security guys at work to change anything. Would it be possible to change the error handling so it is able to continue after an error like this? Especially since I have explicitly disabled Kite and the software works fine if it encounters the error when already running. \r\n\r\n\t2020-04-20 12:05:42,162 [DEBUG] [spyder.plugins.editor.plugin] -> Start completion server for C:\\Users\\[removed]\\.spyder-py3\\temp.py [Python]\r\n\t2020-04-20 12:05:42,162 [DEBUG] [spyder.plugins.editor.plugin] -> Python completion server is ready\r\n\t2020-04-20 12:05:42,164 [DEBUG] [spyder.plugins.editor.widgets.codeeditor] -> Completions services available for: C:\\Users\\[removed]\\.spyder-py3\\temp.py\r\n\t2020-04-20 12:05:42,164 [DEBUG] [spyder.plugins.editor.plugin] -> python completion server request: 'textDocument/didOpen'\r\n\t2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Completion plugin: Request 0 Got response from lsp\r\n\t2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Gather responses for textDocument/didOpen\r\n\t2020-04-20 12:05:42,165 [DEBUG] [spyder.plugins.completion.plugin] -> Completion plugin: Request 0 Got response from kite\r\n\t2020-04-20 12:05:42,166 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Set focus to: C:\\Users\\[removed]\\.spyder-py3\\temp.py\r\n\t2020-04-20 12:05:42,166 [DEBUG] [spyder.plugins.completion.fallback.actor] -> Got request id 0: textDocument/didOpen for file C:\\Users\\[removed]\\.spyder-py3\\temp.py\r\n\t2020-04-20 12:05:42,167 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Current changed: 0 - C:\\Users\\[removed]\\.spyder-py3\\temp.py\r\n\t2020-04-20 12:05:42,170 [DEBUG] [spyder.plugins.editor.widgets.editor] -> Added thread <spyder.plugins.editor.widgets.editor.AnalysisThread object at 0x0000019B03720A68> to queue\r\n\t2020-04-20 12:05:42,189 [INFO] [spyder.app.mainwindow] -> Launching code completion client for Python...\r\n\t2020-04-20 12:05:42,203 [DEBUG] [spyder.plugins.completion.kite.client] -> Starting Kite HTTP session...\r\n\t2020-04-20 12:05:42,208 [DEBUG] [urllib3.connectionpool] -> Starting new HTTP connection (1): [vpn server name].[company name].com:80\r\n\t2020-04-20 12:05:42,512 [DEBUG] [urllib3.connectionpool] -> http://[vpn server name].[company name].com:80 \"GET http://127.0.0.1:46624/clientapi/languages HTTP/1.1\" 200 7277\r\n\tTraceback (most recent call last):\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\app\\mainwindow.py\", line 3718, in main\r\n\t\tmainwindow = run_spyder(app, options, args)\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\app\\mainwindow.py\", line 3559, in run_spyder\r\n\t\tmain.setup()\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\app\\mainwindow.py\", line 960, in setup\r\n\t\tself.completions.start()\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\plugins\\completion\\plugin.py\", line 292, in start\r\n\t\tclient_info['plugin'].start()\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\plugins\\completion\\kite\\plugin.py\", line 144, in start\r\n\t\tself.client.start()\r\n\t  File \"C:\\Progra~1\\Anaconda3\\lib\\site-packages\\spyder\\plugins\\completion\\kite\\client.py\", line 62, in start\r\n\t\tself.sig_client_started.emit(self.languages)\r\n\tTypeError: KiteClient.sig_client_started[list].emit(): argument 1 has unexpected type 'str'\r\n\r\n_Originally posted by @nsluhrs in https://github.com/spyder-ide/spyder/issues/12357#issuecomment-616665440_\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 Spyder Project Contributors\n# Licensed under the terms of the MIT License\n# (see spyder/__init__.py for details)\n\n\"\"\"Kite completions HTTP client.\"\"\"\n\n# Standard library imports\nimport logging\ntry:\n    from urllib import quote  # Python 2\nexcept ImportError:\n    from urllib.parse import quote  # Python 3\n\n# Third party imports\nfrom qtpy.QtCore import QObject, QThread, Signal, QMutex\nimport requests\n\n# Local imports\nfrom spyder.config.base import _\nfrom spyder.plugins.completion.kite import KITE_ENDPOINTS, KITE_REQUEST_MAPPING\nfrom spyder.plugins.completion.kite.decorators import class_register\nfrom spyder.plugins.completion.kite.providers import KiteMethodProviderMixIn\nfrom spyder.plugins.completion.kite.utils.status import (\n    status, check_if_kite_running)\nfrom spyder.py3compat import (\n    ConnectionError, ConnectionRefusedError, TEXT_TYPES)\n\n\nlogger = logging.getLogger(__name__)\n\n\n@class_register\nclass KiteClient(QObject, KiteMethodProviderMixIn):\n    sig_response_ready = Signal(int, dict)\n    sig_client_started = Signal(list)\n    sig_client_not_responding = Signal()\n    sig_perform_request = Signal(int, str, object)\n    sig_perform_status_request = Signal(str)\n    sig_status_response_ready = Signal((str,), (dict,))\n    sig_perform_onboarding_request = Signal()\n    sig_onboarding_response_ready = Signal(str)\n\n    def __init__(self, parent, enable_code_snippets=True):\n        QObject.__init__(self, parent)\n        self.endpoint = None\n        self.requests = {}\n        self.languages = []\n        self.mutex = QMutex()\n        self.opened_files = {}\n        self.opened_files_status = {}\n        self.thread_started = False\n        self.enable_code_snippets = enable_code_snippets\n        self.thread = QThread()\n        self.moveToThread(self.thread)\n        self.thread.started.connect(self.started)\n        self.sig_perform_request.connect(self.perform_request)\n        self.sig_perform_status_request.connect(self.get_status)\n        self.sig_perform_onboarding_request.connect(self.get_onboarding_file)\n\n    def start(self):\n        if not self.thread_started:\n            self.thread.start()\n        logger.debug('Starting Kite HTTP session...')\n        self.endpoint = requests.Session()\n        self.languages = self.get_languages()\n        self.sig_client_started.emit(self.languages)\n\n    def started(self):\n        self.thread_started = True\n\n    def stop(self):\n        if self.thread_started:\n            logger.debug('Closing Kite HTTP session...')\n            self.endpoint.close()\n            self.thread.quit()\n\n    def get_languages(self):\n        verb, url = KITE_ENDPOINTS.LANGUAGES_ENDPOINT\n        success, response = self.perform_http_request(verb, url)\n        if response is None:\n            response = ['python']\n        return response\n\n    def _get_onboarding_file(self):\n        \"\"\"Perform a request to get kite's onboarding file.\"\"\"\n        verb, url = KITE_ENDPOINTS.ONBOARDING_ENDPOINT\n        success, response = self.perform_http_request(verb, url)\n        return response\n\n    def get_onboarding_file(self):\n        \"\"\"Get onboarding file.\"\"\"\n        onboarding_file = self._get_onboarding_file()\n        self.sig_onboarding_response_ready.emit(onboarding_file)\n\n    def _get_status(self, filename):\n        \"\"\"Perform a request to get kite status for a file.\"\"\"\n        verb, url = KITE_ENDPOINTS.STATUS_ENDPOINT\n        if filename:\n            url_params = {'filename': filename}\n        else:\n            url_params = {'filetype': 'python'}\n        success, response = self.perform_http_request(\n            verb, url, url_params=url_params)\n        return success, response\n\n    def get_status(self, filename):\n        \"\"\"Get kite status for a given filename.\"\"\"\n        success_status, kite_status = self._get_status(filename)\n        if not filename or kite_status is None:\n            kite_status = status()\n            self.sig_status_response_ready[str].emit(kite_status)\n        elif isinstance(kite_status, TEXT_TYPES):\n            if not success_status:\n                status_str = status(extra_status=' with errors')\n                long_str = _(\"<code>{error}</code><br><br>\"\n                             \"Note: If you are using a VPN, \"\n                             \"please don't route requests to \"\n                             \"localhost/127.0.0.1 with it\").format(\n                                 error=kite_status)\n            else:\n                status_str = status()\n                long_str = kite_status\n            kite_status_dict = {\n                'status': status_str,\n                'short': status_str,\n                'long': long_str}\n            self.sig_status_response_ready[dict].emit(kite_status_dict)\n        else:\n            self.sig_status_response_ready[dict].emit(kite_status)\n\n    def perform_http_request(self, verb, url, url_params=None, params=None):\n        response = None\n        http_method = getattr(self.endpoint, verb)\n        try:\n            http_response = http_method(url, params=url_params, json=params)\n        except Exception as error:\n            return False, None\n        success = http_response.status_code == 200\n        if success:\n            try:\n                response = http_response.json()\n            except Exception:\n                response = http_response.text\n                response = None if response == '' else response\n        return success, response\n\n    def send(self, method, params, url_params):\n        response = None\n        if self.endpoint is not None and method in KITE_REQUEST_MAPPING:\n            http_verb, path = KITE_REQUEST_MAPPING[method]\n            encoded_url_params = {\n                key: quote(value) if isinstance(value, TEXT_TYPES) else value\n                for (key, value) in url_params.items()}\n            path = path.format(**encoded_url_params)\n            try:\n                success, response = self.perform_http_request(\n                    http_verb, path, params=params)\n            except (ConnectionRefusedError, ConnectionError):\n                return response\n        return response\n\n    def perform_request(self, req_id, method, params):\n        response = None\n        if method in self.sender_registry:\n            logger.debug('Perform {0} request with id {1}'.format(\n                method, req_id))\n            handler_name = self.sender_registry[method]\n            handler = getattr(self, handler_name)\n            response = handler(params)\n            if method in self.handler_registry:\n                converter_name = self.handler_registry[method]\n                converter = getattr(self, converter_name)\n                if response is not None:\n                    response = converter(response)\n        self.sig_response_ready.emit(req_id, response or {})\n", "path": "spyder/plugins/completion/kite/client.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 Spyder Project Contributors\n# Licensed under the terms of the MIT License\n# (see spyder/__init__.py for details)\n\n\"\"\"Kite completions HTTP client.\"\"\"\n\n# Standard library imports\nimport logging\ntry:\n    from urllib import quote  # Python 2\nexcept ImportError:\n    from urllib.parse import quote  # Python 3\n\n# Third party imports\nfrom qtpy.QtCore import QObject, QThread, Signal, QMutex\nimport requests\n\n# Local imports\nfrom spyder.config.base import _\nfrom spyder.plugins.completion.kite import KITE_ENDPOINTS, KITE_REQUEST_MAPPING\nfrom spyder.plugins.completion.kite.decorators import class_register\nfrom spyder.plugins.completion.kite.providers import KiteMethodProviderMixIn\nfrom spyder.plugins.completion.kite.utils.status import (\n    status, check_if_kite_running)\nfrom spyder.py3compat import (\n    ConnectionError, ConnectionRefusedError, TEXT_TYPES)\n\n\nlogger = logging.getLogger(__name__)\n\n\n@class_register\nclass KiteClient(QObject, KiteMethodProviderMixIn):\n    sig_response_ready = Signal(int, dict)\n    sig_client_started = Signal(list)\n    sig_client_not_responding = Signal()\n    sig_perform_request = Signal(int, str, object)\n    sig_perform_status_request = Signal(str)\n    sig_status_response_ready = Signal((str,), (dict,))\n    sig_perform_onboarding_request = Signal()\n    sig_onboarding_response_ready = Signal(str)\n\n    def __init__(self, parent, enable_code_snippets=True):\n        QObject.__init__(self, parent)\n        self.endpoint = None\n        self.requests = {}\n        self.languages = []\n        self.mutex = QMutex()\n        self.opened_files = {}\n        self.opened_files_status = {}\n        self.thread_started = False\n        self.enable_code_snippets = enable_code_snippets\n        self.thread = QThread()\n        self.moveToThread(self.thread)\n        self.thread.started.connect(self.started)\n        self.sig_perform_request.connect(self.perform_request)\n        self.sig_perform_status_request.connect(self.get_status)\n        self.sig_perform_onboarding_request.connect(self.get_onboarding_file)\n\n    def start(self):\n        if not self.thread_started:\n            self.thread.start()\n        logger.debug('Starting Kite HTTP session...')\n        self.endpoint = requests.Session()\n        self.languages = self.get_languages()\n        self.sig_client_started.emit(self.languages)\n\n    def started(self):\n        self.thread_started = True\n\n    def stop(self):\n        if self.thread_started:\n            logger.debug('Closing Kite HTTP session...')\n            self.endpoint.close()\n            self.thread.quit()\n\n    def get_languages(self):\n        verb, url = KITE_ENDPOINTS.LANGUAGES_ENDPOINT\n        success, response = self.perform_http_request(verb, url)\n        if response is None or isinstance(response, TEXT_TYPES):\n            response = ['python']\n        return response\n\n    def _get_onboarding_file(self):\n        \"\"\"Perform a request to get kite's onboarding file.\"\"\"\n        verb, url = KITE_ENDPOINTS.ONBOARDING_ENDPOINT\n        success, response = self.perform_http_request(verb, url)\n        return response\n\n    def get_onboarding_file(self):\n        \"\"\"Get onboarding file.\"\"\"\n        onboarding_file = self._get_onboarding_file()\n        self.sig_onboarding_response_ready.emit(onboarding_file)\n\n    def _get_status(self, filename):\n        \"\"\"Perform a request to get kite status for a file.\"\"\"\n        verb, url = KITE_ENDPOINTS.STATUS_ENDPOINT\n        if filename:\n            url_params = {'filename': filename}\n        else:\n            url_params = {'filetype': 'python'}\n        success, response = self.perform_http_request(\n            verb, url, url_params=url_params)\n        return success, response\n\n    def get_status(self, filename):\n        \"\"\"Get kite status for a given filename.\"\"\"\n        success_status, kite_status = self._get_status(filename)\n        if not filename or kite_status is None:\n            kite_status = status()\n            self.sig_status_response_ready[str].emit(kite_status)\n        elif isinstance(kite_status, TEXT_TYPES):\n            status_str = status(extra_status=' with errors')\n            long_str = _(\"<code>{error}</code><br><br>\"\n                         \"Note: If you are using a VPN, \"\n                         \"please don't route requests to \"\n                         \"localhost/127.0.0.1 with it\").format(\n                             error=kite_status)\n            kite_status_dict = {\n                'status': status_str,\n                'short': status_str,\n                'long': long_str}\n            self.sig_status_response_ready[dict].emit(kite_status_dict)\n        else:\n            self.sig_status_response_ready[dict].emit(kite_status)\n\n    def perform_http_request(self, verb, url, url_params=None, params=None):\n        response = None\n        http_method = getattr(self.endpoint, verb)\n        try:\n            http_response = http_method(url, params=url_params, json=params)\n        except Exception as error:\n            return False, None\n        success = http_response.status_code == 200\n        if success:\n            try:\n                response = http_response.json()\n            except Exception:\n                response = http_response.text\n                response = None if response == '' else response\n        return success, response\n\n    def send(self, method, params, url_params):\n        response = None\n        if self.endpoint is not None and method in KITE_REQUEST_MAPPING:\n            http_verb, path = KITE_REQUEST_MAPPING[method]\n            encoded_url_params = {\n                key: quote(value) if isinstance(value, TEXT_TYPES) else value\n                for (key, value) in url_params.items()}\n            path = path.format(**encoded_url_params)\n            try:\n                success, response = self.perform_http_request(\n                    http_verb, path, params=params)\n            except (ConnectionRefusedError, ConnectionError):\n                return response\n        return response\n\n    def perform_request(self, req_id, method, params):\n        response = None\n        if method in self.sender_registry:\n            logger.debug('Perform {0} request with id {1}'.format(\n                method, req_id))\n            handler_name = self.sender_registry[method]\n            handler = getattr(self, handler_name)\n            response = handler(params)\n            if method in self.handler_registry:\n                converter_name = self.handler_registry[method]\n                converter = getattr(self, converter_name)\n                if response is not None:\n                    response = converter(response)\n        self.sig_response_ready.emit(req_id, response or {})\n", "path": "spyder/plugins/completion/kite/client.py"}]}