Skip to content

Commit 03ab6ef

Browse files
authored
Fix skipping imported symbols (#53)
1 parent 32bbc06 commit 03ab6ef

File tree

6 files changed

+42
-15
lines changed

6 files changed

+42
-15
lines changed

Diff for: CONFIGURATION.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This server can be configured using `workspace/didChangeConfiguration` method. E
3232
| `pylsp.plugins.jedi_signature_help.enabled` | `boolean` | Enable or disable the plugin. | `true` |
3333
| `pylsp.plugins.jedi_symbols.enabled` | `boolean` | Enable or disable the plugin. | `true` |
3434
| `pylsp.plugins.jedi_symbols.all_scopes` | `boolean` | If True lists the names of all scopes instead of only the module namespace. | `true` |
35+
| `pylsp.plugins.jedi_symbols.include_import_symbols` | `boolean` | If True includes symbols imported from other libraries. | `true` |
3536
| `pylsp.plugins.mccabe.enabled` | `boolean` | Enable or disable the plugin. | `true` |
3637
| `pylsp.plugins.mccabe.threshold` | `number` | The minimum threshold that triggers warnings about cyclomatic complexity. | `15` |
3738
| `pylsp.plugins.preload.enabled` | `boolean` | Enable or disable the plugin. | `true` |

Diff for: pylsp/config/schema.json

+5
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@
157157
"default": true,
158158
"description": "If True lists the names of all scopes instead of only the module namespace."
159159
},
160+
"pylsp.plugins.jedi_symbols.include_import_symbols": {
161+
"type": "boolean",
162+
"default": true,
163+
"description": "If True includes symbols imported from other libraries."
164+
},
160165
"pylsp.plugins.mccabe.enabled": {
161166
"type": "boolean",
162167
"default": true,

Diff for: pylsp/plugins/symbols.py

+30-12
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,46 @@ def pylsp_document_symbols(config, document):
1919
symbols_settings = config.plugin_settings('jedi_symbols')
2020
all_scopes = symbols_settings.get('all_scopes', True)
2121
add_import_symbols = symbols_settings.get('include_import_symbols', True)
22-
23-
use_document_path = False
24-
document_dir = os.path.normpath(os.path.dirname(document.path))
25-
if not os.path.isfile(os.path.join(document_dir, '__init__.py')):
26-
use_document_path = True
27-
28-
definitions = document.jedi_names(use_document_path, all_scopes=all_scopes)
29-
module_name = document.dot_path
22+
definitions = document.jedi_names(all_scopes=all_scopes)
3023
symbols = []
3124
exclude = set({})
3225
redefinitions = {}
3326
while definitions != []:
3427
d = definitions.pop(0)
28+
29+
# Skip symbols imported from other modules.
3530
if not add_import_symbols:
31+
# Skip if there's an import in the code the symbol is defined.
32+
code = d.get_line_code()
33+
if ' import ' in code or 'import ' in code:
34+
continue
35+
36+
# Skip comparing module names.
3637
sym_full_name = d.full_name
38+
module_name = document.dot_path
3739
if sym_full_name is not None:
38-
if (not sym_full_name.startswith(module_name) and
39-
not sym_full_name.startswith('__main__')):
40-
continue
40+
# module_name returns where the symbol is imported, whereas
41+
# full_name says where it really comes from. So if the parent
42+
# modules in full_name are not in module_name, it means the
43+
# symbol was not defined there.
44+
# Note: The last element of sym_full_name is the symbol itself,
45+
# so we don't need to use it below.
46+
imported_symbol = True
47+
for mod in sym_full_name.split('.')[:-1]:
48+
if mod in module_name:
49+
imported_symbol = False
50+
51+
# When there's no __init__.py next to a file or in one of its
52+
# parents, the check above fails. However, Jedi has a nice way
53+
# to tell if the symbol was declared in the same file: if
54+
# full_name starts by __main__.
55+
if imported_symbol:
56+
if not sym_full_name.startswith('__main__'):
57+
continue
58+
4159
try:
4260
docismodule = os.path.samefile(document.path, d.module_path)
43-
except TypeError:
61+
except (TypeError, FileNotFoundError):
4462
# Python 2 on Windows has no .samefile, but then these are
4563
# strings for sure
4664
docismodule = document.path == d.module_path

Diff for: pylsp/python_lsp.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,8 @@ def m_text_document__signature_help(self, textDocument=None, position=None, **_k
383383
return self.signature_help(textDocument['uri'], position)
384384

385385
def m_workspace__did_change_configuration(self, settings=None):
386-
self.config.update((settings or {}).get('pylsp', {}))
386+
if self.config is not None:
387+
self.config.update((settings or {}).get('pylsp', {}))
387388
for workspace in self.workspaces.values():
388389
workspace.update_config(settings)
389390
for doc_uri in workspace.documents:

Diff for: pylsp/workspace.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ def word_at_position(self, position):
239239
return m_start[0] + m_end[-1]
240240

241241
@lock
242-
def jedi_names(self, use_document_path, all_scopes=False, definitions=True, references=False):
243-
script = self.jedi_script(use_document_path=use_document_path)
242+
def jedi_names(self, all_scopes=False, definitions=True, references=False):
243+
script = self.jedi_script()
244244
return script.get_names(all_scopes=all_scopes, definitions=definitions,
245245
references=references)
246246

Diff for: test/test_language_server.py

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
from threading import Thread
99

10+
from flaky import flaky
1011
from pylsp_jsonrpc.exceptions import JsonRpcMethodNotFound
1112
import pytest
1213

@@ -75,6 +76,7 @@ def client_exited_server():
7576
assert client_server_pair.process.is_alive() is False
7677

7778

79+
@flaky(max_runs=10, min_passes=1)
7880
@pytest.mark.skipif(sys.platform == 'darwin', reason='Too flaky on Mac')
7981
def test_initialize(client_server): # pylint: disable=redefined-outer-name
8082
response = client_server._endpoint.request('initialize', {

0 commit comments

Comments
 (0)