1
1
# Copyright 2022- Python Language Server Contributors.
2
2
3
- from typing import Dict , List
4
- from unittest .mock import Mock
3
+ from typing import Any , Dict , List
4
+ from unittest .mock import Mock , patch
5
+
6
+ from test .test_notebook_document import wait_for_condition
7
+ from test .test_utils import send_initialize_request , send_notebook_did_open
5
8
6
9
import jedi
7
10
import parso
8
11
import pytest
9
12
10
- from pylsp import lsp , uris
13
+ from pylsp import IS_WIN , lsp , uris
11
14
from pylsp .config .config import Config
12
15
from pylsp .plugins .rope_autoimport import _get_score , _should_insert , get_names
13
16
from pylsp .plugins .rope_autoimport import (
16
19
from pylsp .plugins .rope_autoimport import pylsp_initialize
17
20
from pylsp .workspace import Workspace
18
21
22
+
19
23
DOC_URI = uris .from_fs_path (__file__ )
20
24
21
25
26
+ def contains_autoimport (suggestion : Dict [str , Any ], module : str ) -> bool :
27
+ """Checks if `suggestion` contains an autoimport for `module`."""
28
+ return suggestion .get ("label" , "" ) == module and "import" in suggestion .get (
29
+ "detail" , ""
30
+ )
31
+
32
+
22
33
@pytest .fixture (scope = "session" )
23
34
def autoimport_workspace (tmp_path_factory ) -> Workspace :
24
35
"Special autoimport workspace. Persists across sessions to make in-memory sqlite3 database fast."
@@ -39,7 +50,9 @@ def completions(config: Config, autoimport_workspace: Workspace, request):
39
50
com_position = {"line" : 0 , "character" : position }
40
51
autoimport_workspace .put_document (DOC_URI , source = document )
41
52
doc = autoimport_workspace .get_document (DOC_URI )
42
- yield pylsp_autoimport_completions (config , autoimport_workspace , doc , com_position )
53
+ yield pylsp_autoimport_completions (
54
+ config , autoimport_workspace , doc , com_position , None
55
+ )
43
56
autoimport_workspace .rm_document (DOC_URI )
44
57
45
58
@@ -141,45 +154,13 @@ def test_autoimport_defined_name(config, workspace):
141
154
com_position = {"line" : 1 , "character" : 3 }
142
155
workspace .put_document (DOC_URI , source = document )
143
156
doc = workspace .get_document (DOC_URI )
144
- completions = pylsp_autoimport_completions (config , workspace , doc , com_position )
157
+ completions = pylsp_autoimport_completions (
158
+ config , workspace , doc , com_position , None
159
+ )
145
160
workspace .rm_document (DOC_URI )
146
161
assert not check_dict ({"label" : "List" }, completions )
147
162
148
163
149
- # This test has several large issues.
150
- # 1. autoimport relies on its sources being written to disk. This makes testing harder
151
- # 2. the hook doesn't handle removed files
152
- # 3. The testing framework cannot access the actual autoimport object so it cannot clear the cache
153
- # def test_autoimport_update_module(config: Config, workspace: Workspace):
154
- # document2 = "SomethingYouShouldntWrite = 1"
155
- # document = """SomethingYouShouldntWrit"""
156
- # com_position = {
157
- # "line": 0,
158
- # "character": 3,
159
- # }
160
- # doc2_path = workspace.root_path + "/test_file_no_one_should_write_to.py"
161
- # if os.path.exists(doc2_path):
162
- # os.remove(doc2_path)
163
- # DOC2_URI = uris.from_fs_path(doc2_path)
164
- # workspace.put_document(DOC_URI, source=document)
165
- # doc = workspace.get_document(DOC_URI)
166
- # completions = pylsp_autoimport_completions(config, workspace, doc, com_position)
167
- # assert len(completions) == 0
168
- # with open(doc2_path, "w") as f:
169
- # f.write(document2)
170
- # workspace.put_document(DOC2_URI, source=document2)
171
- # doc2 = workspace.get_document(DOC2_URI)
172
- # pylsp_document_did_save(config, workspace, doc2)
173
- # assert check_dict({"label": "SomethingYouShouldntWrite"}, completions)
174
- # workspace.put_document(DOC2_URI, source="\n")
175
- # doc2 = workspace.get_document(DOC2_URI)
176
- # os.remove(doc2_path)
177
- # pylsp_document_did_save(config, workspace, doc2)
178
- # completions = pylsp_autoimport_completions(config, workspace, doc, com_position)
179
- # assert len(completions) == 0
180
- # workspace.rm_document(DOC_URI)
181
-
182
-
183
164
class TestShouldInsert :
184
165
def test_dot (self ):
185
166
assert not should_insert ("""str.""" , 4 )
@@ -233,3 +214,74 @@ class sfa:
233
214
"""
234
215
results = get_names (jedi .Script (code = source ))
235
216
assert results == set (["blah" , "bleh" , "e" , "hello" , "someone" , "sfa" , "a" , "b" ])
217
+
218
+
219
+ @pytest .mark .skipif (IS_WIN , reason = "Flaky on Windows" )
220
+ def test_autoimport_for_notebook_document (
221
+ client_server_pair ,
222
+ ):
223
+ client , server = client_server_pair
224
+ send_initialize_request (client )
225
+
226
+ with patch .object (server ._endpoint , "notify" ) as mock_notify :
227
+ # Expectations:
228
+ # 1. We receive an autoimport suggestion for "os" in the first cell because
229
+ # os is imported after that.
230
+ # 2. We don't receive an autoimport suggestion for "os" in the second cell because it's
231
+ # already imported in the second cell.
232
+ # 3. We don't receive an autoimport suggestion for "os" in the third cell because it's
233
+ # already imported in the second cell.
234
+ # 4. We receive an autoimport suggestion for "sys" because it's not already imported
235
+ send_notebook_did_open (client , ["os" , "import os\n os" , "os" , "sys" ])
236
+ wait_for_condition (lambda : mock_notify .call_count >= 3 )
237
+
238
+ server .m_workspace__did_change_configuration (
239
+ settings = {
240
+ "pylsp" : {"plugins" : {"rope_autoimport" : {"enabled" : True , "memory" : True }}}
241
+ }
242
+ )
243
+ rope_autoimport_settings = server .workspace ._config .plugin_settings (
244
+ "rope_autoimport"
245
+ )
246
+ assert rope_autoimport_settings .get ("enabled" , False ) is True
247
+ assert rope_autoimport_settings .get ("memory" , False ) is True
248
+
249
+ # 1.
250
+ suggestions = server .completions ("cell_1_uri" , {"line" : 0 , "character" : 2 }).get (
251
+ "items"
252
+ )
253
+ assert any (
254
+ suggestion
255
+ for suggestion in suggestions
256
+ if contains_autoimport (suggestion , "os" )
257
+ )
258
+
259
+ # 2.
260
+ suggestions = server .completions ("cell_2_uri" , {"line" : 1 , "character" : 2 }).get (
261
+ "items"
262
+ )
263
+ assert not any (
264
+ suggestion
265
+ for suggestion in suggestions
266
+ if contains_autoimport (suggestion , "os" )
267
+ )
268
+
269
+ # 3.
270
+ suggestions = server .completions ("cell_3_uri" , {"line" : 0 , "character" : 2 }).get (
271
+ "items"
272
+ )
273
+ assert not any (
274
+ suggestion
275
+ for suggestion in suggestions
276
+ if contains_autoimport (suggestion , "os" )
277
+ )
278
+
279
+ # 4.
280
+ suggestions = server .completions ("cell_4_uri" , {"line" : 0 , "character" : 3 }).get (
281
+ "items"
282
+ )
283
+ assert any (
284
+ suggestion
285
+ for suggestion in suggestions
286
+ if contains_autoimport (suggestion , "sys" )
287
+ )
0 commit comments