1
1
# -*- coding: utf-8 -*-
2
2
"""
3
- File that contains the python-lsp-server plugin mypy-ls .
3
+ File that contains the python-lsp-server plugin pylsp-mypy .
4
4
5
5
Created on Fri Jul 10 09:53:57 2020
6
6
10
10
import tempfile
11
11
import os
12
12
import os .path
13
+ from pathlib import Path
13
14
import logging
14
15
from mypy import api as mypy_api
15
16
from pylsp import hookimpl
24
25
log = logging .getLogger (__name__ )
25
26
26
27
# A mapping from workspace path to config file path
27
- mypyConfigFileMap : Dict [str , Optional [str ]] = dict ()
28
+ mypyConfigFileMap : Dict [str , Optional [str ]] = {}
28
29
29
30
tmpFile : Optional [IO [str ]] = None
30
31
33
34
# so store a cache of last diagnostics for each file a-la the pylint plugin,
34
35
# so we can return some potentially-stale diagnostics.
35
36
# https://github.com/python-lsp/python-lsp-server/blob/v1.0.1/pylsp/plugins/pylint_lint.py#L55-L62
36
- last_diagnostics : Dict [str , List ] = collections .defaultdict (list )
37
+ last_diagnostics : Dict [str , List [ Dict [ str , Any ]] ] = collections .defaultdict (list )
37
38
38
39
39
- def parse_line (
40
- line : str , document : Optional [Document ] = None
41
- ) -> Optional [Dict [str , Any ]]:
40
+ def parse_line (line : str , document : Optional [Document ] = None ) -> Optional [Dict [str , Any ]]:
42
41
"""
43
42
Return a language-server diagnostic from a line of the Mypy error report.
44
43
@@ -66,9 +65,7 @@ def parse_line(
66
65
# results from other files can be included, but we cannot return
67
66
# them.
68
67
if document and document .path and not document .path .endswith (file_path ):
69
- log .warning (
70
- "discarding result for %s against %s" , file_path , document .path
71
- )
68
+ log .warning ("discarding result for %s against %s" , file_path , document .path )
72
69
return None
73
70
74
71
lineno = int (linenoStr or 1 ) - 1 # 0-based line number
@@ -91,9 +88,7 @@ def parse_line(
91
88
# can make a good guess by highlighting the word that Mypy flagged
92
89
word = document .word_at_position (diag ["range" ]["start" ])
93
90
if word :
94
- diag ["range" ]["end" ]["character" ] = diag ["range" ]["start" ][
95
- "character"
96
- ] + len (word )
91
+ diag ["range" ]["end" ]["character" ] = diag ["range" ]["start" ]["character" ] + len (word )
97
92
98
93
return diag
99
94
return None
@@ -123,7 +118,22 @@ def pylsp_lint(
123
118
List of the linting data.
124
119
125
120
"""
126
- settings = config .plugin_settings ("mypy-ls" )
121
+ settings = config .plugin_settings ("pylsp_mypy" )
122
+ oldSettings1 = config .plugin_settings ("mypy-ls" )
123
+ if oldSettings1 != {}:
124
+ raise DeprecationWarning (
125
+ "Your configuration uses the namespace mypy-ls, this should be changed to pylsp_mypy"
126
+ )
127
+ oldSettings2 = config .plugin_settings ("mypy_ls" )
128
+ if oldSettings2 != {}:
129
+ raise DeprecationWarning (
130
+ "Your configuration uses the namespace mypy_ls, this should be changed to pylsp_mypy"
131
+ )
132
+ if settings == {}:
133
+ settings = oldSettings1
134
+ if settings == {}:
135
+ settings = oldSettings2
136
+
127
137
log .info (
128
138
"lint settings = %s document.path = %s is_saved = %s" ,
129
139
settings ,
@@ -143,9 +153,12 @@ def pylsp_lint(
143
153
args = ["--show-column-numbers" ]
144
154
145
155
global tmpFile
146
- if live_mode and not is_saved and tmpFile :
147
- log .info ("live_mode tmpFile = %s" , live_mode )
148
- tmpFile = open (tmpFile .name , "w" )
156
+ if live_mode and not is_saved :
157
+ if tmpFile :
158
+ tmpFile = open (tmpFile .name , "w" )
159
+ else :
160
+ tmpFile = tempfile .NamedTemporaryFile ("w" , delete = False )
161
+ log .info ("live_mode tmpFile = %s" , tmpFile .name )
149
162
tmpFile .write (document .source )
150
163
tmpFile .close ()
151
164
args .extend (["--shadow-file" , document .path , tmpFile .name ])
@@ -181,9 +194,7 @@ def pylsp_lint(
181
194
# In either case, reset to fresh state
182
195
_ , _err , _status = mypy_api .run_dmypy (["status" ])
183
196
if _status != 0 :
184
- log .info (
185
- "restarting dmypy from status: %s message: %s" , _status , _err .strip ()
186
- )
197
+ log .info ("restarting dmypy from status: %s message: %s" , _status , _err .strip ())
187
198
mypy_api .run_dmypy (["kill" ])
188
199
189
200
# run to use existing daemon or restart if required
@@ -201,7 +212,7 @@ def pylsp_lint(
201
212
if diag :
202
213
diagnostics .append (diag )
203
214
204
- log .info ("mypy-ls len(diagnostics) = %s" , len (diagnostics ))
215
+ log .info ("pylsp-mypy len(diagnostics) = %s" , len (diagnostics ))
205
216
206
217
last_diagnostics [document .path ] = diagnostics
207
218
return diagnostics
@@ -224,7 +235,7 @@ def pylsp_settings(config: Config) -> Dict[str, Dict[str, Dict[str, str]]]:
224
235
225
236
"""
226
237
configuration = init (config ._root_path )
227
- return {"plugins" : {"mypy-ls " : configuration }}
238
+ return {"plugins" : {"pylsp_mypy " : configuration }}
228
239
229
240
230
241
def init (workspace : str ) -> Dict [str , str ]:
@@ -242,33 +253,22 @@ def init(workspace: str) -> Dict[str, str]:
242
253
The plugin config dict.
243
254
244
255
"""
245
- # On windows the path contains \\ on linux it contains / all the code works with /
246
256
log .info ("init workspace = %s" , workspace )
247
- workspace = workspace .replace ("\\ " , "/" )
248
257
249
258
configuration = {}
250
- path = findConfigFile (workspace , " mypy-ls.cfg" )
259
+ path = findConfigFile (workspace , [ "pylsp- mypy.cfg" , "mypy -ls.cfg", "mypy_ls.cfg" ] )
251
260
if path :
252
261
with open (path ) as file :
253
262
configuration = eval (file .read ())
254
263
255
- mypyConfigFile = findConfigFile (workspace , "mypy.ini" )
256
- if not mypyConfigFile :
257
- mypyConfigFile = findConfigFile (workspace , ".mypy.ini" )
264
+ mypyConfigFile = findConfigFile (workspace , ["mypy.ini" , ".mypy.ini" ])
258
265
mypyConfigFileMap [workspace ] = mypyConfigFile
259
266
260
- if ("enabled" not in configuration or configuration ["enabled" ]) and (
261
- "live_mode" not in configuration or configuration ["live_mode" ]
262
- ):
263
- global tmpFile
264
- tmpFile = tempfile .NamedTemporaryFile ("w" , delete = False )
265
- tmpFile .close ()
266
-
267
267
log .info ("mypyConfigFile = %s configuration = %s" , mypyConfigFile , configuration )
268
268
return configuration
269
269
270
270
271
- def findConfigFile (path : str , name : str ) -> Optional [str ]:
271
+ def findConfigFile (path : str , names : List [ str ] ) -> Optional [str ]:
272
272
"""
273
273
Search for a config file.
274
274
@@ -279,24 +279,28 @@ def findConfigFile(path: str, name: str) -> Optional[str]:
279
279
----------
280
280
path : str
281
281
The path where the search starts.
282
- name : str
283
- The file to be found.
282
+ names : List[ str]
283
+ The file to be found (or alternative names) .
284
284
285
285
Returns
286
286
-------
287
287
Optional[str]
288
288
The path where the file has been found or None if no matching file has been found.
289
289
290
290
"""
291
- while True :
292
- p = f"{ path } /{ name } "
293
- if os .path .isfile (p ):
294
- return p
295
- else :
296
- loc = path .rfind ("/" )
297
- if loc == - 1 :
298
- return None
299
- path = path [:loc ]
291
+ start = Path (path ).joinpath (names [0 ]) # the join causes the parents to include path
292
+ for parent in start .parents :
293
+ for name in names :
294
+ file = parent .joinpath (name )
295
+ if file .is_file ():
296
+ if file .name in ["mypy-ls.cfg" , "mypy_ls.cfg" ]:
297
+ raise DeprecationWarning (
298
+ f"{ str (file )} : { file .name } is no longer supported, you should rename your "
299
+ "config file to pylsp-mypy.cfg"
300
+ )
301
+ return str (file )
302
+
303
+ return None
300
304
301
305
302
306
@atexit .register
0 commit comments