Repository: palantir/python-language-server
Pull request #87 (2017-08-07 12:18:31)

Handle windows paths in workspace.get_uri_like + test
Fix for #85 where windows paths were not prefixed and converted to forward slashes

tomv564: Sounds like a good idea, I'll add quoting. 
It will try to (unnecessarily) encode the `:` in `/D:/myfile` which I'd like to avoid.
I couldn't find any reason why module_path is sometimes None, please let me know if my assumption was correct!

Patch:
diff --git a/README.rst b/README.rst
index e41469b..506ca8a 100644
--- a/README.rst
+++ b/README.rst
@@ -61,8 +61,8 @@ Develop against VS Code
 
 The Python language server can be developed against a local instance of Visual Studio Code.
 
-1. Install [VSCode for Mac](http://code.visualstudio.com/docs/?dv=osx)
-2. From within VSCode View -> Command Palette, then type _shell_ and run ``install 'code' command in PATH``
+1. Install `VSCode for Mac <http://code.visualstudio.com/docs/?dv=osx>`_
+2. From within VSCode View -> Command Palette, then type *shell* and run ``install 'code' command in PATH``
 
 .. code-block:: bash
 
diff --git a/pyls/config.py b/pyls/config.py
index 4ab4193..8f88b02 100644
--- a/pyls/config.py
+++ b/pyls/config.py
@@ -68,8 +68,12 @@ def find_parents(root, path, names):
     Note:
         The path MUST be within the root.
     """
+    if not root:
+        return []
     if not os.path.commonprefix((root, path)):
-        raise ValueError("Path %s not in %s" % (path, root))
+        log.warning("Path %s not in %s", path, root)
+        return []
+
     curdir = os.path.dirname(path)
 
     while curdir != os.path.dirname(root) and curdir != '/':
diff --git a/pyls/plugins/definition.py b/pyls/plugins/definition.py
index cd1e4dd..0e79a79 100644
--- a/pyls/plugins/definition.py
+++ b/pyls/plugins/definition.py
@@ -12,8 +12,9 @@ def pyls_definitions(document, position):
         d for d in definitions
         if d.is_definition() and d.line is not None and d.column is not None
     ]
+
     return [{
-        'uri': workspace.get_uri_like(document.uri, d.module_path),
+        'uri': workspace.get_uri_like(document.uri, d.module_path) if d.module_path else document.uri,
         'range': {
             'start': {'line': d.line - 1, 'character': d.column},
             'end': {'line': d.line - 1, 'character': d.column + len(d.name)}
diff --git a/pyls/plugins/references.py b/pyls/plugins/references.py
index ad338bd..c77e26c 100644
--- a/pyls/plugins/references.py
+++ b/pyls/plugins/references.py
@@ -15,7 +15,7 @@ def pyls_references(document, position, exclude_declaration=False):
         usages = [d for d in usages if not d.is_definition()]
 
     return [{
-        'uri': workspace.get_uri_like(document.uri, d.module_path),
+        'uri': workspace.get_uri_like(document.uri, d.module_path) if d.module_path else document.uri,
         'range': {
             'start': {'line': d.line - 1, 'character': d.column},
             'end': {'line': d.line - 1, 'character': d.column + len(d.name)}
diff --git a/pyls/workspace.py b/pyls/workspace.py
index 10e6f50..29f898d 100644
--- a/pyls/workspace.py
+++ b/pyls/workspace.py
@@ -4,7 +4,7 @@ import logging
 import os
 import re
 import sys
-from urllib.parse import urlparse, urlunparse, unquote
+from urllib.parse import urlparse, urlunparse, quote, unquote
 
 import jedi
 
@@ -72,7 +72,7 @@ class Workspace(object):
         return path
 
     def is_in_workspace(self, path):
-        return os.path.commonprefix((self.root, path))
+        return not self.root or os.path.commonprefix((self.root, path))
 
 
 class Document(object):
@@ -181,5 +181,10 @@ def get_uri_like(doc_uri, path):
     unicode objects.
     """
     parts = list(urlparse(doc_uri))
+    if path[0] != '/' and ':' in path:  # fix path for windows
+        drivespec, path = path.split(':', 1)
+        path = '/' + drivespec + ':' + quote(path.replace('\\', '/'))
+    else:
+        path = quote(path)
     parts[2] = path
     return urlunparse([str(p) for p in parts])


Test patch:
diff --git a/test/test_workspace.py b/test/test_workspace.py
index 37cbf2d..a66c192 100644
--- a/test/test_workspace.py
+++ b/test/test_workspace.py
@@ -36,6 +36,10 @@ def test_bad_get_document(pyls):
 
 def test_uri_like():
     assert workspace.get_uri_like('file:///some-path', '/my/path') == 'file:///my/path'
+    win_doc_uri = r'file:///D:/hello%20world.py'
+    win_doc_path = r'D:\hello world.py'
+    win_uri = workspace.get_uri_like(win_doc_uri, win_doc_path)
+    assert win_uri == win_doc_uri
 
 
 def test_non_root_project(pyls):