1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# Copyright 2017-2020 Palantir Technologies, Inc.
# Copyright 2021- Python Language Server Contributors.
import os
import sys
import pytest
from pylsp import uris
from pylsp.lsp import SymbolKind
from pylsp.plugins.symbols import pylsp_document_symbols
from pylsp.workspace import Document
PY2 = sys.version[0] == "2"
LINUX = sys.platform.startswith("linux")
CI = os.environ.get("CI")
DOC_URI = uris.from_fs_path(__file__)
DOC = """import sys
a = 'hello'
class B:
def __init__(self):
x = 2
self.y = x
def main(x):
y = 2 * x
return y
"""
DOC_IMPORTS = """from . import something
from ..module import something
from module import (a, b)
def main():
# import ignored
print("from module import x") # string with import
return something
"""
def helper_check_symbols_all_scope(symbols):
# All eight symbols (import sys, a, B, __init__, x, y, main, y)
assert len(symbols) == 8
def sym(name):
return [s for s in symbols if s["name"] == name][0]
# Check we have some sane mappings to VSCode constants
assert sym("a")["kind"] == SymbolKind.Variable
assert sym("B")["kind"] == SymbolKind.Class
assert sym("__init__")["kind"] == SymbolKind.Method
assert sym("main")["kind"] == SymbolKind.Function
# Not going to get too in-depth here else we're just testing Jedi
assert sym("a")["location"]["range"]["start"] == {"line": 2, "character": 0}
def test_symbols(config, workspace):
doc = Document(DOC_URI, workspace, DOC)
config.update({"plugins": {"jedi_symbols": {"all_scopes": False}}})
symbols = pylsp_document_symbols(config, doc)
# All four symbols (import sys, a, B, main)
# y is not in the root scope, it shouldn't be returned
assert len(symbols) == 5
def sym(name):
return [s for s in symbols if s["name"] == name][0]
# Check we have some sane mappings to VSCode constants
assert sym("a")["kind"] == SymbolKind.Variable
assert sym("B")["kind"] == SymbolKind.Class
assert sym("main")["kind"] == SymbolKind.Function
# Not going to get too in-depth here else we're just testing Jedi
assert sym("a")["location"]["range"]["start"] == {"line": 2, "character": 0}
# Ensure that the symbol range spans the whole definition
assert sym("main")["location"]["range"]["start"] == {"line": 9, "character": 0}
assert sym("main")["location"]["range"]["end"] == {"line": 12, "character": 0}
def test_symbols_complex_imports(config, workspace):
doc = Document(DOC_URI, workspace, DOC_IMPORTS)
config.update({"plugins": {"jedi_symbols": {"all_scopes": False}}})
symbols = pylsp_document_symbols(config, doc)
import_symbols = [s for s in symbols if s["kind"] == SymbolKind.Module]
assert len(import_symbols) == 4
names = [s["name"] for s in import_symbols]
assert "something" in names
assert "a" in names or "b" in names
assert any(
s["name"] == "main" and s["kind"] == SymbolKind.Function for s in symbols
)
def test_symbols_all_scopes(config, workspace) -> None:
doc = Document(DOC_URI, workspace, DOC)
symbols = pylsp_document_symbols(config, doc)
helper_check_symbols_all_scope(symbols)
def test_symbols_non_existing_file(config, workspace, tmpdir) -> None:
path = tmpdir.join("foo.py")
# Check pre-condition: file must not exist
assert not path.check(exists=1)
doc = Document(uris.from_fs_path(str(path)), workspace, DOC)
symbols = pylsp_document_symbols(config, doc)
helper_check_symbols_all_scope(symbols)
@pytest.mark.skipif(
PY2 or not LINUX or not CI, reason="tested on linux and python 3 only"
)
def test_symbols_all_scopes_with_jedi_environment(workspace) -> None:
doc = Document(DOC_URI, workspace, DOC)
# Update config extra environment
env_path = "/tmp/pyenv/bin/python"
settings = {"pylsp": {"plugins": {"jedi": {"environment": env_path}}}}
doc.update_config(settings)
symbols = pylsp_document_symbols(doc._config, doc)
helper_check_symbols_all_scope(symbols)
|