11# Copyright 2022- Python Language Server Contributors.
22
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
58
69import jedi
710import parso
811import pytest
912
10- from pylsp import lsp , uris
13+ from pylsp import IS_WIN , lsp , uris
1114from pylsp .config .config import Config
1215from pylsp .plugins .rope_autoimport import _get_score , _should_insert , get_names
1316from pylsp .plugins .rope_autoimport import (
1619from pylsp .plugins .rope_autoimport import pylsp_initialize
1720from pylsp .workspace import Workspace
1821
22+
1923DOC_URI = uris .from_fs_path (__file__ )
2024
2125
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+
2233@pytest .fixture (scope = "session" )
2334def autoimport_workspace (tmp_path_factory ) -> Workspace :
2435 "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):
3950 com_position = {"line" : 0 , "character" : position }
4051 autoimport_workspace .put_document (DOC_URI , source = document )
4152 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+ )
4356 autoimport_workspace .rm_document (DOC_URI )
4457
4558
@@ -141,45 +154,13 @@ def test_autoimport_defined_name(config, workspace):
141154 com_position = {"line" : 1 , "character" : 3 }
142155 workspace .put_document (DOC_URI , source = document )
143156 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+ )
145160 workspace .rm_document (DOC_URI )
146161 assert not check_dict ({"label" : "List" }, completions )
147162
148163
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-
183164class TestShouldInsert :
184165 def test_dot (self ):
185166 assert not should_insert ("""str.""" , 4 )
@@ -233,3 +214,74 @@ class sfa:
233214 """
234215 results = get_names (jedi .Script (code = source ))
235216 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