11# -*- coding: utf-8 -*-
22"""
3- File that contains the python-lsp-server plugin mypy-ls .
3+ File that contains the python-lsp-server plugin pylsp-mypy .
44
55Created on Fri Jul 10 09:53:57 2020
66
1010import tempfile
1111import os
1212import os .path
13+ from pathlib import Path
1314import logging
1415from mypy import api as mypy_api
1516from pylsp import hookimpl
2425log = logging .getLogger (__name__ )
2526
2627# A mapping from workspace path to config file path
27- mypyConfigFileMap : Dict [str , Optional [str ]] = dict ()
28+ mypyConfigFileMap : Dict [str , Optional [str ]] = {}
2829
2930tmpFile : Optional [IO [str ]] = None
3031
3334# so store a cache of last diagnostics for each file a-la the pylint plugin,
3435# so we can return some potentially-stale diagnostics.
3536# 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 )
3738
3839
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 ]]:
4241 """
4342 Return a language-server diagnostic from a line of the Mypy error report.
4443
@@ -66,9 +65,7 @@ def parse_line(
6665 # results from other files can be included, but we cannot return
6766 # them.
6867 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 )
7269 return None
7370
7471 lineno = int (linenoStr or 1 ) - 1 # 0-based line number
@@ -91,9 +88,7 @@ def parse_line(
9188 # can make a good guess by highlighting the word that Mypy flagged
9289 word = document .word_at_position (diag ["range" ]["start" ])
9390 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 )
9792
9893 return diag
9994 return None
@@ -123,7 +118,22 @@ def pylsp_lint(
123118 List of the linting data.
124119
125120 """
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+
127137 log .info (
128138 "lint settings = %s document.path = %s is_saved = %s" ,
129139 settings ,
@@ -143,9 +153,12 @@ def pylsp_lint(
143153 args = ["--show-column-numbers" ]
144154
145155 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 )
149162 tmpFile .write (document .source )
150163 tmpFile .close ()
151164 args .extend (["--shadow-file" , document .path , tmpFile .name ])
@@ -181,9 +194,7 @@ def pylsp_lint(
181194 # In either case, reset to fresh state
182195 _ , _err , _status = mypy_api .run_dmypy (["status" ])
183196 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 ())
187198 mypy_api .run_dmypy (["kill" ])
188199
189200 # run to use existing daemon or restart if required
@@ -201,7 +212,7 @@ def pylsp_lint(
201212 if diag :
202213 diagnostics .append (diag )
203214
204- log .info ("mypy-ls len(diagnostics) = %s" , len (diagnostics ))
215+ log .info ("pylsp-mypy len(diagnostics) = %s" , len (diagnostics ))
205216
206217 last_diagnostics [document .path ] = diagnostics
207218 return diagnostics
@@ -224,7 +235,7 @@ def pylsp_settings(config: Config) -> Dict[str, Dict[str, Dict[str, str]]]:
224235
225236 """
226237 configuration = init (config ._root_path )
227- return {"plugins" : {"mypy-ls " : configuration }}
238+ return {"plugins" : {"pylsp_mypy " : configuration }}
228239
229240
230241def init (workspace : str ) -> Dict [str , str ]:
@@ -242,33 +253,22 @@ def init(workspace: str) -> Dict[str, str]:
242253 The plugin config dict.
243254
244255 """
245- # On windows the path contains \\ on linux it contains / all the code works with /
246256 log .info ("init workspace = %s" , workspace )
247- workspace = workspace .replace ("\\ " , "/" )
248257
249258 configuration = {}
250- path = findConfigFile (workspace , " mypy-ls.cfg" )
259+ path = findConfigFile (workspace , [ "pylsp- mypy.cfg" , "mypy -ls.cfg", "mypy_ls.cfg" ] )
251260 if path :
252261 with open (path ) as file :
253262 configuration = eval (file .read ())
254263
255- mypyConfigFile = findConfigFile (workspace , "mypy.ini" )
256- if not mypyConfigFile :
257- mypyConfigFile = findConfigFile (workspace , ".mypy.ini" )
264+ mypyConfigFile = findConfigFile (workspace , ["mypy.ini" , ".mypy.ini" ])
258265 mypyConfigFileMap [workspace ] = mypyConfigFile
259266
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-
267267 log .info ("mypyConfigFile = %s configuration = %s" , mypyConfigFile , configuration )
268268 return configuration
269269
270270
271- def findConfigFile (path : str , name : str ) -> Optional [str ]:
271+ def findConfigFile (path : str , names : List [ str ] ) -> Optional [str ]:
272272 """
273273 Search for a config file.
274274
@@ -279,24 +279,28 @@ def findConfigFile(path: str, name: str) -> Optional[str]:
279279 ----------
280280 path : str
281281 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) .
284284
285285 Returns
286286 -------
287287 Optional[str]
288288 The path where the file has been found or None if no matching file has been found.
289289
290290 """
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
300304
301305
302306@atexit .register
0 commit comments