# Path: langserver/fs.py
# class RemoteFileSystem(FileSystem):
#     def __init__(self, conn: JSONRPC2Connection):
#         self.conn = conn
# 
#     def open(self, path, parent_span=None):
#         if parent_span is None:
#             resp = self.conn.send_request("textDocument/xcontent", {
#                 "textDocument": {
#                     "uri": "file://" + path
#                 }
#             })
#             if "error" in resp:
#                 raise FileException(resp["error"])
#             return resp["result"]["text"]
# 
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.open") as open_span:
#             open_span.set_tag("path", path)
#             resp = self.conn.send_request("textDocument/xcontent", {
#                 "textDocument": {
#                     "uri": "file://" + path
#                 }
#             })
#             if "error" in resp:
#                 raise FileException(resp["error"])
#             return resp["result"]["text"]
# 
#     def listdir(self, path, parent_span=None):
#         if parent_span is None:
#             return self._listdir(path)
# 
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.listdir") as list_span:
#             list_span.set_tag("path", path)
#             # TODO(keegan) Use workspace/xfiles + cache
#             return self._listdir(path)
# 
#     def _listdir(self, path):
#         resp = self.conn.send_request("fs/readDir", path)
#         if resp.get("error") is not None:
#             raise FileException(resp["error"])
#         entries = []
#         for e in resp["result"]:
#             entries.append(e["name"])
#         return entries
# 
#     def walk(self, path):
#         resp = self.conn.send_request("workspace/xfiles",
#                                       {"base": "file://" + path})
#         if "error" in resp:
#             raise FileException(resp["error"])
#         for doc in resp["result"]:
#             uri = doc["uri"]
#             if uri.startswith("file://"):
#                 yield uri[7:]
#             else:
#                 yield uri
# 
#     def batch_open(self, paths, parent_span):
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.batch_open"):
#             # We need to read the iterator paths twice, so convert to list
#             paths = list(paths)
#             responses = self.conn.send_request_batch(("textDocument/xcontent",
#                                                       {
#                                                           "textDocument": {
#                                                               "uri":
#                                                               "file://" + path
#                                                           }
#                                                       }) for path in paths)
#             for path, resp in zip(paths, responses):
#                 if "error" in resp:
#                     # Consume rest of generator to ensure resources are
#                     # shutdown
#                     for _ in responses:
#                         pass
#                     raise FileException(resp["error"])
#                 yield (path, resp["result"]["text"])
# 
# class TestFileSystem(FileSystem):
#     def __init__(self, local_root_path: str):
#         self.root = os.path.abspath(local_root_path)
# 
#     def open(self, path: str, parent_span=None):
#         if os.path.isabs(path):
#             path = os.path.join(self.root, os.path.relpath(path, "/"))
#         else:
#             path = os.path.join(self.root, path)
#         with open(path) as open_file:
#             return open_file.read()
# 
#     def batch_open(self, paths, parent_span):
#         for path in paths:
#             yield (path, self.open(path))
# 
#     def listdir(self, path: str, parent_span=None):
#         path = os.path.abspath(path)
#         # need this check for namespace imports, for which we get a relative
#         # path
#         if not path.startswith(self.root):
#             if path.startswith("/"):
#                 path = path[1:]
#             path = os.path.join(self.root, path)
#         return [os.path.join(path, p) for p in os.listdir(path)]
# 
#     def walk(self, top: str):
#         yield from (os.path.join("/", p) for p in self._walk(top))
# 
#     def _walk(self, top: str):
#         dir = self.listdir(top)
#         files, dirs = [], []
#         for e in dir:
#             if os.path.isdir(e):
#                 dirs.append(os.path.relpath(e, self.root))
#             else:
#                 files.append(os.path.relpath(e, self.root))
#         yield from files
#         for d in dirs:
#             yield from self._walk(os.path.join(self.root, d))


from os import path as filepath
from typing import List
from .fs import RemoteFileSystem, TestFileSystem
import os
import jedi
import jedi._compatibility
import opentracing
                        fullname, [module_path])
                    is_package = False
                elif is_package and module_path.endswith(".py"):
                    module_path = filepath.dirname(module_path)
                return module_file, module_path, is_package

        # TODO: update this to use the workspace's module indices
        def list_modules() -> List[str]:
            if trace:
                print("list_modules")
            modules = [
                f for f in self.fs.walk(self.root_path)
                if f.lower().endswith(".py")
            ]
            return modules

        def load_source(path) -> str:
            with opentracing.start_child_span(
                    parent_span, "load_source_callback") as load_source_span:
                load_source_span.set_tag("path", path)
                if trace:
                    print("load_source", path)
                result = self.fs.open(path, load_source_span)
                return result

        # TODO(keegan) It shouldn't matter if we are using a remote fs or not.
        # Consider other ways to hook into the import system.
        # TODO(aaron) Also, it shouldn't matter whether we're using a "real"
        # filesystem or our test harness filesystem
        if isinstance(self.fs, RemoteFileSystem) or isinstance(

# Path: langserver/fs.py
# class RemoteFileSystem(FileSystem):
#     def __init__(self, conn: JSONRPC2Connection):
#         self.conn = conn
# 
#     def open(self, path, parent_span=None):
#         if parent_span is None:
#             resp = self.conn.send_request("textDocument/xcontent", {
#                 "textDocument": {
#                     "uri": "file://" + path
#                 }
#             })
#             if "error" in resp:
#                 raise FileException(resp["error"])
#             return resp["result"]["text"]
# 
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.open") as open_span:
#             open_span.set_tag("path", path)
#             resp = self.conn.send_request("textDocument/xcontent", {
#                 "textDocument": {
#                     "uri": "file://" + path
#                 }
#             })
#             if "error" in resp:
#                 raise FileException(resp["error"])
#             return resp["result"]["text"]
# 
#     def listdir(self, path, parent_span=None):
#         if parent_span is None:
#             return self._listdir(path)
# 
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.listdir") as list_span:
#             list_span.set_tag("path", path)
#             # TODO(keegan) Use workspace/xfiles + cache
#             return self._listdir(path)
# 
#     def _listdir(self, path):
#         resp = self.conn.send_request("fs/readDir", path)
#         if resp.get("error") is not None:
#             raise FileException(resp["error"])
#         entries = []
#         for e in resp["result"]:
#             entries.append(e["name"])
#         return entries
# 
#     def walk(self, path):
#         resp = self.conn.send_request("workspace/xfiles",
#                                       {"base": "file://" + path})
#         if "error" in resp:
#             raise FileException(resp["error"])
#         for doc in resp["result"]:
#             uri = doc["uri"]
#             if uri.startswith("file://"):
#                 yield uri[7:]
#             else:
#                 yield uri
# 
#     def batch_open(self, paths, parent_span):
#         with opentracing.start_child_span(
#                 parent_span, "RemoteFileSystem.batch_open"):
#             # We need to read the iterator paths twice, so convert to list
#             paths = list(paths)
#             responses = self.conn.send_request_batch(("textDocument/xcontent",
#                                                       {
#                                                           "textDocument": {
#                                                               "uri":
#                                                               "file://" + path
#                                                           }
#                                                       }) for path in paths)
#             for path, resp in zip(paths, responses):
#                 if "error" in resp:
#                     # Consume rest of generator to ensure resources are
#                     # shutdown
#                     for _ in responses:
#                         pass
#                     raise FileException(resp["error"])
#                 yield (path, resp["result"]["text"])
# 
# class TestFileSystem(FileSystem):
#     def __init__(self, local_root_path: str):
#         self.root = os.path.abspath(local_root_path)
# 
#     def open(self, path: str, parent_span=None):
#         if os.path.isabs(path):
#             path = os.path.join(self.root, os.path.relpath(path, "/"))
#         else:
#             path = os.path.join(self.root, path)
#         with open(path) as open_file:
#             return open_file.read()
# 
#     def batch_open(self, paths, parent_span):
#         for path in paths:
#             yield (path, self.open(path))
# 
#     def listdir(self, path: str, parent_span=None):
#         path = os.path.abspath(path)
#         # need this check for namespace imports, for which we get a relative
#         # path
#         if not path.startswith(self.root):
#             if path.startswith("/"):
#                 path = path[1:]
#             path = os.path.join(self.root, path)
#         return [os.path.join(path, p) for p in os.listdir(path)]
# 
#     def walk(self, top: str):
#         yield from (os.path.join("/", p) for p in self._walk(top))
# 
#     def _walk(self, top: str):
#         dir = self.listdir(top)
#         files, dirs = [], []
#         for e in dir:
#             if os.path.isdir(e):
#                 dirs.append(os.path.relpath(e, self.root))
#             else:
#                 files.append(os.path.relpath(e, self.root))
#         yield from files
#         for d in dirs:
#             yield from self._walk(os.path.join(self.root, d))


# Path: langserver/jedi.py
from os import path as filepath
from typing import List
from .fs import RemoteFileSystem, TestFileSystem
import os
import jedi
import jedi._compatibility
import opentracing

                        fullname, [module_path])
                    is_package = False
                elif is_package and module_path.endswith(".py"):
                    module_path = filepath.dirname(module_path)
                return module_file, module_path, is_package

        # TODO: update this to use the workspace's module indices
        def list_modules() -> List[str]:
            if trace:
                print("list_modules")
            modules = [
                f for f in self.fs.walk(self.root_path)
                if f.lower().endswith(".py")
            ]
            return modules

        def load_source(path) -> str:
            with opentracing.start_child_span(
                    parent_span, "load_source_callback") as load_source_span:
                load_source_span.set_tag("path", path)
                if trace:
                    print("load_source", path)
                result = self.fs.open(path, load_source_span)
                return result

        # TODO(keegan) It shouldn't matter if we are using a remote fs or not.
        # Consider other ways to hook into the import system.
        # TODO(aaron) Also, it shouldn't matter whether we're using a "real"
        # filesystem or our test harness filesystem
        if isinstance(self.fs, RemoteFileSystem) or isinstance(

                self.fs, TestFileSystem):