Skip to content
This repository was archived by the owner on Mar 27, 2019. It is now read-only.

Commit 66417ef

Browse files
committed
wip
1 parent 44c3b0b commit 66417ef

File tree

7 files changed

+615
-534
lines changed

7 files changed

+615
-534
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ lint:
99

1010
test:
1111
# pipenv run pytest test_langserver.py
12-
cd ./test && pipenv run pytest test_fizzbuzz.py
12+
cd ./test && pipenv run pytest test_fizzbuzz.py -vv

Pipfile.lock

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

langserver/clone_workspace.py

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
from shutil import rmtree
77
import delegator
88
import json
9+
from functools import lru_cache
10+
from enum import Enum
11+
import pathlib
912

1013
log = logging.getLogger(__name__)
1114

@@ -15,6 +18,7 @@ class CloneWorkspace:
1518
def __init__(self, fs: FileSystem, project_root: str,
1619
original_root_path: str= ""):
1720

21+
self.fs = fs
1822
self.PROJECT_ROOT = project_root
1923
self.repo = None
2024
self.hash = None
@@ -35,40 +39,39 @@ def __init__(self, fs: FileSystem, project_root: str,
3539
if self.hash:
3640
self.key = ".".join((self.key, self.hash))
3741

38-
# TODO: allow different Python versions per project/workspace
39-
self.PYTHON_PATH = GlobalConfig.PYTHON_PATH
42+
self.PYTHON_PATH = os.path.abspath(GlobalConfig.PYTHON_PATH)
4043
self.CLONED_PROJECT_PATH = os.path.abspath(os.path.join(
4144
GlobalConfig.CLONED_PROJECT_PATH, self.key))
45+
4246
log.debug("Setting Python path to %s", self.PYTHON_PATH)
4347
log.debug("Setting Cloned Project path to %s",
4448
self.CLONED_PROJECT_PATH)
4549

46-
self.fs = fs
47-
4850
# Clone the project from the provided filesystem into the local
4951
# cache
5052
all_files = self.fs.walk(self.PROJECT_ROOT)
5153
for file_path in all_files:
52-
cache_file_path = self.to_cache_path(file_path)
53-
if os.path.exists(cache_file_path):
54-
continue
54+
cache_file_path = self.project_to_cache_path(file_path)
5555

5656
os.makedirs(os.path.dirname(cache_file_path), exist_ok=True)
5757
file_contents = self.fs.open(file_path)
5858
with open(cache_file_path, "w") as f:
5959
f.write(file_contents)
6060

61+
@property
62+
@lru_cache()
63+
def VENV_LOCATION(self):
6164
self.ensure_venv_created()
62-
self.VENV_LOCATION = self.run_command("pipenv --venv").out
65+
return self.run_command("pipenv --venv").out.rstrip()
6366

6467
def cleanup(self):
65-
log.info("Removing project's virtual emvironment %s", self.VENV_LOCATION)
68+
log.info("Removing project's virtual environment %s", self.VENV_LOCATION)
6669
self.remove_venv()
6770

6871
log.info("Removing cloned project cache %s", self.CLONED_PROJECT_PATH)
6972
rmtree(self.CLONED_PROJECT_PATH, ignore_errors=True)
7073

71-
def to_cache_path(self, project_path):
74+
def project_to_cache_path(self, project_path):
7275
"""
7376
Translates a path from the root of the project to the equivalent path in
7477
the local cache.
@@ -80,7 +83,7 @@ def to_cache_path(self, project_path):
8083

8184
return os.path.join(self.CLONED_PROJECT_PATH, file_path)
8285

83-
def from_cache_path(self, cache_path):
86+
def cache_path_to_project_path(self, cache_path):
8487
"""
8588
Translates a path in the cache to the equivalent path in
8689
the project.
@@ -100,7 +103,37 @@ def ensure_venv_created(self):
100103
self.run_command("true")
101104

102105
def remove_venv(self):
103-
self.run_command("pipenv --rm")
106+
self.run_command("pipenv --rm", no_prefix=True)
107+
108+
def get_module_info(self, raw_module_path):
109+
module_path = pathlib.Path(raw_module_path)
110+
111+
import pdb
112+
pdb.set_trace()
113+
114+
sys_std_lib_path = pathlib.Path(self.PYTHON_PATH)
115+
if sys_std_lib_path in module_path.parents:
116+
return (ModuleKind.STANDARD_LIBRARY, path.relative_to(sys_std_lib_path))
117+
118+
venv_path = pathlib.Path(self.VENV_LOCATION) / "lib"
119+
if venv_path in module_path.parents:
120+
# The python libraries in a venv are stored under
121+
# VENV_LOCATION/lib/(some_python_version)
122+
123+
python_version = module_path.relative_to(venv_path).parts[0]
124+
125+
venv_lib_path = venv_path / python_version
126+
venv_ext_packages_path = venv_lib_path / "site-packages"
127+
128+
if venv_ext_packages_path in module_path.parents:
129+
return (ModuleKind.EXTERNAL_DEPENDENCY, module_path.relative_to(venv_ext_packages_path))
130+
return (ModuleKind.STANDARD_LIBRARY, module_path.relative_to(venv_lib_path))
131+
132+
project_path = pathlib.Path(self.CLONED_PROJECT_PATH)
133+
if project_path in module_path.parents:
134+
return (ModuleKind.PROJECT, module_path.relative_to(project_path))
135+
136+
return (ModuleKind.UNKNOWN, module_path)
104137

105138
def get_package_information(self):
106139
project_packages = self.project_packages()
@@ -116,6 +149,7 @@ def get_package_information(self):
116149
})
117150
return out
118151

152+
@lru_cache()
119153
def project_packages(self):
120154
'''
121155
Provides a list of all packages declared in the project
@@ -150,11 +184,11 @@ def external_dependencies(self):
150184
for dep in deps:
151185
dep_name = dep["name"]
152186
if dep_name not in set(["pip", "wheel"]):
153-
out.append({"attributes": {"name": dep["name"]}})
187+
out.append({"attributes": {"name": dep_name}})
154188

155189
return out
156190

157-
def run_command(self, command, **kwargs):
191+
def run_command(self, command, no_prefix=False, **kwargs):
158192
'''
159193
Runs the given command inside the context
160194
of the project:
@@ -167,9 +201,17 @@ def run_command(self, command, **kwargs):
167201
kwargs["cwd"] = self.CLONED_PROJECT_PATH
168202

169203
# add pipenv prefix
170-
if type(command) is str:
171-
command = "pipenv run {}".format(command)
172-
else:
173-
command = ["pipenv", "run"].append(command)
204+
if not no_prefix:
205+
if type(command) is str:
206+
command = "pipenv run {}".format(command)
207+
else:
208+
command = ["pipenv", "run"].append(command)
174209

175210
return delegator.run(command, **kwargs)
211+
212+
213+
class ModuleKind(Enum):
214+
PROJECT = 1
215+
STANDARD_LIBRARY = 2
216+
EXTERNAL_DEPENDENCY = 3
217+
UNKNOWN = 4

langserver/jedi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def _new_script_impl(self, parent_span, *args, **kwargs):
3232
del kwargs['trace']
3333

3434
if self.workspace is not None:
35-
path = self.workspace.to_cache_path(path)
35+
path = self.workspace.project_to_cache_path(path)
3636
venv_path = self.workspace.VENV_LOCATION
3737

3838
kwargs.update(

langserver/langserver.py

Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .symbols import extract_symbols, workspace_symbols
1616
from .definitions import targeted_symbol
1717
from .references import get_references
18-
from .clone_workspace import CloneWorkspace
18+
from .clone_workspace import CloneWorkspace, ModuleKind
1919

2020
log = logging.getLogger(__name__)
2121

@@ -344,63 +344,61 @@ def serve_x_definition(self, request):
344344
return results
345345

346346
for d in defs:
347-
defining_module_path = d.module_path
348-
defining_module = self.workspace.get_module_by_path(
349-
defining_module_path)
347+
kind, module_path = ModuleKind.UNKNOWN, ""
348+
if d.module_path:
349+
kind, module_path = self.workspace.get_module_info(
350+
d.module_path)
350351

351-
if not defining_module and (not d.is_definition() or
352-
d.line is None or d.column is None):
352+
if (not d.is_definition() or
353+
d.line is None or d.column is None):
353354
continue
354355

355356
symbol_locator = {"symbol": None, "location": None}
356357

357-
if defining_module and not defining_module.is_stdlib:
358-
# the module path doesn't map onto the repository structure
359-
# because we're not fully installing
360-
# dependency packages, so don't include it in the symbol
361-
# descriptor
362-
filename = os.path.basename(defining_module_path)
363-
symbol_name = ""
364-
symbol_kind = ""
365-
if d.description:
366-
symbol_name, symbol_kind = LangServer.name_and_kind(
367-
d.description)
368-
symbol_locator["symbol"] = {
369-
"package": {
370-
"name": defining_module.qualified_name.split(".")[0],
371-
},
372-
"name": symbol_name,
373-
"container": defining_module.qualified_name,
374-
"kind": symbol_kind,
375-
"file": filename
376-
}
377-
378-
elif defining_module and defining_module.is_stdlib:
379-
rel_path = os.path.relpath(defining_module_path,
380-
self.workspace.PYTHON_PATH)
381-
filename = os.path.basename(defining_module_path)
382-
symbol_name = ""
383-
symbol_kind = ""
384-
if d.description:
385-
symbol_name, symbol_kind = LangServer.name_and_kind(
386-
d.description)
387-
symbol_locator["symbol"] = {
388-
"package": {
389-
"name": "cpython",
390-
},
391-
"name": symbol_name,
392-
"container": defining_module.qualified_name,
393-
"kind": symbol_kind,
394-
"path": os.path.join(GlobalConfig.STDLIB_SRC_PATH,
395-
rel_path),
396-
"file": filename
397-
}
358+
if kind is not ModuleKind.UNKNOWN:
359+
if kind == ModuleKind.STANDARD_LIBRARY:
360+
filename = module_path.name
361+
symbol_name = ""
362+
symbol_kind = ""
363+
if d.description:
364+
symbol_name, symbol_kind = LangServer.name_and_kind(
365+
d.description)
366+
symbol_locator["symbol"] = {
367+
"package": {
368+
"name": "cpython",
369+
},
370+
"name": symbol_name,
371+
"container": d.full_name,
372+
"kind": symbol_kind,
373+
"path": str(GlobalConfig.STDLIB_SRC_PATH / module_path),
374+
"file": filename
375+
}
376+
else:
377+
# the module path doesn't map onto the repository structure
378+
# because we're not fully installing
379+
# dependency packages, so don't include it in the symbol
380+
# descriptor
381+
filename = module_path.name
382+
symbol_name = ""
383+
symbol_kind = ""
384+
if d.description:
385+
symbol_name, symbol_kind = LangServer.name_and_kind(
386+
d.description)
387+
symbol_locator["symbol"] = {
388+
"package": {
389+
"name": d.full_name.split(".")[0],
390+
},
391+
"name": symbol_name,
392+
"container": d.full_name,
393+
"kind": symbol_kind,
394+
"file": filename
395+
}
398396

399397
if (d.is_definition() and
400398
d.line is not None and d.column is not None):
401399
location = {
402400
# TODO(renfred) determine why d.module_path is empty.
403-
"uri": "file://" + (d.module_path or path),
401+
"uri": "file://" + (str(module_path) or path),
404402
"range": {
405403
"start": {
406404
"line": d.line - 1,
@@ -419,7 +417,7 @@ def serve_x_definition(self, request):
419417
"start"]
420418

421419
# set the full location if the definition is in this workspace
422-
if not defining_module or not defining_module.is_external:
420+
if not kind in [ModuleKind.UNKNOWN, ModuleKind.EXTERNAL_DEPENDENCY]:
423421
symbol_locator["location"] = location
424422

425423
results.append(symbol_locator)

test/.cache/v/cache/lastfailed

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,45 @@
1-
{}
1+
{
2+
"test_clone_workspace.py::TestCloningWorkspace::()::test_clone": true,
3+
"test_conflictingdeps.py::TestConflictingDependencies::()::test_hover_packages_conflicting_module_names": true,
4+
"test_dep_versioning.py::TestDependencyVersioning::()::test_dep_download_specified_version[test_data0]": true,
5+
"test_dep_versioning.py::TestDependencyVersioning::()::test_dep_download_specified_version[test_data1]": true,
6+
"test_dep_versioning.py::TestDependencyVersioning::()::test_dep_download_specified_version[test_data2]": true,
7+
"test_dep_versioning.py::TestDependencyVersioning::()::test_dep_download_specified_version[test_data3]": true,
8+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_cross_package_definition": true,
9+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_cross_package_import_definition": true,
10+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_local_defintion": true,
11+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_local_package_cross_module_definition": true,
12+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_local_package_cross_module_import_definition": true,
13+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_local_references": true,
14+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_std_lib_definition": true,
15+
"test_fizzbuzz.py::TestFizzBuzzWorkspace::()::test_x_references": true,
16+
"test_fizzbuzz.py::test_cross_package_definition": true,
17+
"test_fizzbuzz.py::test_cross_package_import_definition": true,
18+
"test_fizzbuzz.py::test_local_defintion": true,
19+
"test_fizzbuzz.py::test_local_package_cross_module_definition": true,
20+
"test_fizzbuzz.py::test_local_package_cross_module_import_definition": true,
21+
"test_fizzbuzz.py::test_local_references": true,
22+
"test_fizzbuzz.py::test_std_lib_definition": true,
23+
"test_fizzbuzz.py::test_x_packages": true,
24+
"test_flask.py::test_cross_module_definition": true,
25+
"test_flask.py::test_cross_module_hover": true,
26+
"test_flask.py::test_cross_package_definition": true,
27+
"test_flask.py::test_cross_package_hover": true,
28+
"test_flask.py::test_cross_repo_definition": true,
29+
"test_flask.py::test_cross_repo_hover": true,
30+
"test_flask.py::test_cross_repo_import_definition": true,
31+
"test_flask.py::test_definition_of_definition": true,
32+
"test_flask.py::test_local_definition": true,
33+
"test_flask.py::test_local_package_import_definition": true,
34+
"test_flask.py::test_local_references": true,
35+
"test_flask.py::test_stdlib_definition": true,
36+
"test_flask.py::test_x_packages": true,
37+
"test_global_variables.py::test_name_definition": true,
38+
"test_graphql_core.py::test_relative_import_definition": true,
39+
"test_jedi.py::test_absolute_import_definiton": true,
40+
"test_jedi.py::test_x_packages": true,
41+
"test_modpkgsamename.py::TestExtPkgHasModuleWithSameName::()::test_hover_pkg_module_same_name": true,
42+
"test_tensorflow_models.py::test_ad_hoc_module_definition": true,
43+
"test_tensorflow_models.py::test_namespace_package_definition": true,
44+
"test_thefuck.py::test_local_references": true
45+
}

0 commit comments

Comments
 (0)