vscode-common-python-lsp 0.3.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/PKG-INFO +1 -1
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/pyproject.toml +1 -1
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_process_runner.py +130 -1
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/__init__.py +8 -1
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/process_runner.py +65 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp.egg-info/PKG-INFO +1 -1
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/README.md +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/setup.cfg +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_code_actions.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_context.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_debug.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_diagnostics.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_formatting.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_jsonrpc.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_linting.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_notebook.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_package.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_paths.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_runner.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_server.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_version.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/code_actions.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/context.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/debug.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/diagnostics.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/formatting.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/jsonrpc.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/linting.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/notebook.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/paths.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/runner.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/server.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/version.py +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp.egg-info/SOURCES.txt +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp.egg-info/dependency_links.txt +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp.egg-info/requires.txt +0 -0
- {vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp.egg-info/top_level.txt +0 -0
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_process_runner.py
RENAMED
|
@@ -8,7 +8,12 @@ import unittest
|
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
from unittest.mock import MagicMock
|
|
10
10
|
|
|
11
|
-
from vscode_common_python_lsp.process_runner import
|
|
11
|
+
from vscode_common_python_lsp.process_runner import (
|
|
12
|
+
resolve_bundle_path,
|
|
13
|
+
run_message_loop,
|
|
14
|
+
update_environ_path,
|
|
15
|
+
update_sys_path,
|
|
16
|
+
)
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
class TestUpdateSysPath(unittest.TestCase):
|
|
@@ -60,6 +65,54 @@ class TestUpdateSysPath(unittest.TestCase):
|
|
|
60
65
|
sys.path[:] = original
|
|
61
66
|
|
|
62
67
|
|
|
68
|
+
class TestUpdateEnvironPath(unittest.TestCase):
|
|
69
|
+
"""Tests for update_environ_path."""
|
|
70
|
+
|
|
71
|
+
def test_adds_scripts_to_path(self):
|
|
72
|
+
import sysconfig
|
|
73
|
+
|
|
74
|
+
scripts = sysconfig.get_path("scripts")
|
|
75
|
+
if not scripts:
|
|
76
|
+
self.skipTest("sysconfig does not report scripts path")
|
|
77
|
+
|
|
78
|
+
# Remove scripts from PATH if present
|
|
79
|
+
original_env = os.environ.copy()
|
|
80
|
+
path_var = "PATH" if "PATH" in os.environ else "Path"
|
|
81
|
+
paths = os.environ.get(path_var, "").split(os.pathsep)
|
|
82
|
+
paths = [p for p in paths if p != scripts]
|
|
83
|
+
os.environ[path_var] = os.pathsep.join(paths)
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
update_environ_path()
|
|
87
|
+
new_paths = os.environ[path_var].split(os.pathsep)
|
|
88
|
+
assert scripts in new_paths
|
|
89
|
+
assert new_paths[0] == scripts
|
|
90
|
+
finally:
|
|
91
|
+
os.environ.clear()
|
|
92
|
+
os.environ.update(original_env)
|
|
93
|
+
|
|
94
|
+
def test_does_not_duplicate(self):
|
|
95
|
+
import sysconfig
|
|
96
|
+
|
|
97
|
+
scripts = sysconfig.get_path("scripts")
|
|
98
|
+
if not scripts:
|
|
99
|
+
self.skipTest("sysconfig does not report scripts path")
|
|
100
|
+
|
|
101
|
+
original_env = os.environ.copy()
|
|
102
|
+
path_var = "PATH" if "PATH" in os.environ else "Path"
|
|
103
|
+
# Ensure scripts is already in PATH
|
|
104
|
+
os.environ[path_var] = scripts + os.pathsep + os.environ.get(path_var, "")
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
count_before = os.environ[path_var].split(os.pathsep).count(scripts)
|
|
108
|
+
update_environ_path()
|
|
109
|
+
count_after = os.environ[path_var].split(os.pathsep).count(scripts)
|
|
110
|
+
assert count_after == count_before
|
|
111
|
+
finally:
|
|
112
|
+
os.environ.clear()
|
|
113
|
+
os.environ.update(original_env)
|
|
114
|
+
|
|
115
|
+
|
|
63
116
|
@dataclass
|
|
64
117
|
class _MockResult:
|
|
65
118
|
"""Minimal result object for testing."""
|
|
@@ -254,5 +307,81 @@ class TestRunMessageLoop(unittest.TestCase):
|
|
|
254
307
|
assert "Unknown method: unknown_method" in sent["error"]
|
|
255
308
|
|
|
256
309
|
|
|
310
|
+
class TestBootstrapSysPath(unittest.TestCase):
|
|
311
|
+
"""Tests for resolve_bundle_path (and its alias bootstrap_sys_path)."""
|
|
312
|
+
|
|
313
|
+
def test_adds_tool_and_libs_dirs(self):
|
|
314
|
+
"""resolve_bundle_path adds both tool/ and libs/ to sys.path."""
|
|
315
|
+
import tempfile
|
|
316
|
+
|
|
317
|
+
original = sys.path[:]
|
|
318
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
319
|
+
# Create the expected directory layout:
|
|
320
|
+
# <tmp>/tool/lsp_server.py
|
|
321
|
+
# <tmp>/libs/
|
|
322
|
+
tool_dir = os.path.join(tmp, "tool")
|
|
323
|
+
libs_dir = os.path.join(tmp, "libs")
|
|
324
|
+
os.makedirs(tool_dir)
|
|
325
|
+
os.makedirs(libs_dir)
|
|
326
|
+
script = os.path.join(tool_dir, "lsp_server.py")
|
|
327
|
+
open(script, "w").close()
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
result = resolve_bundle_path(script)
|
|
331
|
+
assert result == tmp
|
|
332
|
+
assert tool_dir in sys.path
|
|
333
|
+
assert libs_dir in sys.path
|
|
334
|
+
# Both should be at the front of sys.path (before original entries)
|
|
335
|
+
assert sys.path.index(tool_dir) < len(original)
|
|
336
|
+
assert sys.path.index(libs_dir) < len(original)
|
|
337
|
+
finally:
|
|
338
|
+
sys.path[:] = original
|
|
339
|
+
|
|
340
|
+
def test_returns_bundle_dir_path(self):
|
|
341
|
+
"""resolve_bundle_path returns the bundle directory."""
|
|
342
|
+
import tempfile
|
|
343
|
+
|
|
344
|
+
original = sys.path[:]
|
|
345
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
346
|
+
tool_dir = os.path.join(tmp, "tool")
|
|
347
|
+
libs_dir = os.path.join(tmp, "libs")
|
|
348
|
+
os.makedirs(tool_dir)
|
|
349
|
+
os.makedirs(libs_dir)
|
|
350
|
+
script = os.path.join(tool_dir, "lsp_server.py")
|
|
351
|
+
open(script, "w").close()
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
result = resolve_bundle_path(script)
|
|
355
|
+
assert result == tmp
|
|
356
|
+
finally:
|
|
357
|
+
sys.path[:] = original
|
|
358
|
+
|
|
359
|
+
def test_respects_ls_import_strategy_env(self):
|
|
360
|
+
"""When LS_IMPORT_STRATEGY=fromEnvironment, libs are appended."""
|
|
361
|
+
import tempfile
|
|
362
|
+
|
|
363
|
+
original = sys.path[:]
|
|
364
|
+
original_env = os.environ.copy()
|
|
365
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
366
|
+
tool_dir = os.path.join(tmp, "tool")
|
|
367
|
+
libs_dir = os.path.join(tmp, "libs")
|
|
368
|
+
os.makedirs(tool_dir)
|
|
369
|
+
os.makedirs(libs_dir)
|
|
370
|
+
script = os.path.join(tool_dir, "lsp_server.py")
|
|
371
|
+
open(script, "w").close()
|
|
372
|
+
|
|
373
|
+
os.environ["LS_IMPORT_STRATEGY"] = "fromEnvironment"
|
|
374
|
+
try:
|
|
375
|
+
len_before = len(sys.path)
|
|
376
|
+
resolve_bundle_path(script)
|
|
377
|
+
assert libs_dir in sys.path
|
|
378
|
+
# libs should be appended after existing entries
|
|
379
|
+
assert sys.path.index(libs_dir) >= len_before
|
|
380
|
+
finally:
|
|
381
|
+
sys.path[:] = original
|
|
382
|
+
os.environ.clear()
|
|
383
|
+
os.environ.update(original_env)
|
|
384
|
+
|
|
385
|
+
|
|
257
386
|
if __name__ == "__main__":
|
|
258
387
|
unittest.main()
|
|
@@ -59,7 +59,12 @@ from .paths import (
|
|
|
59
59
|
normalize_path,
|
|
60
60
|
reset_caches,
|
|
61
61
|
)
|
|
62
|
-
from .process_runner import
|
|
62
|
+
from .process_runner import (
|
|
63
|
+
resolve_bundle_path,
|
|
64
|
+
run_message_loop,
|
|
65
|
+
update_environ_path,
|
|
66
|
+
update_sys_path,
|
|
67
|
+
)
|
|
63
68
|
from .runner import CustomIO, RunResult, run_api, run_module, run_path
|
|
64
69
|
from .server import ToolServer, ToolServerConfig
|
|
65
70
|
from .version import VersionInfo, check_min_version, extract_version, version_to_tuple
|
|
@@ -98,6 +103,8 @@ __all__ = [
|
|
|
98
103
|
"shutdown_json_rpc",
|
|
99
104
|
# process_runner
|
|
100
105
|
"update_sys_path",
|
|
106
|
+
"update_environ_path",
|
|
107
|
+
"resolve_bundle_path",
|
|
101
108
|
"run_message_loop",
|
|
102
109
|
# debug
|
|
103
110
|
"setup_debugpy",
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
+
import pathlib
|
|
8
9
|
import sys
|
|
10
|
+
import sysconfig
|
|
9
11
|
import traceback
|
|
10
12
|
from collections.abc import Callable
|
|
11
13
|
from typing import TYPE_CHECKING
|
|
@@ -34,6 +36,69 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
|
|
|
34
36
|
sys.path.append(path_to_add)
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
def resolve_bundle_path(script_file: str) -> str:
|
|
40
|
+
"""Resolve the bundle directory and configure ``sys.path`` for a bundled LSP server.
|
|
41
|
+
|
|
42
|
+
Call this at the top of your ``lsp_server.py`` (before importing
|
|
43
|
+
any bundled libraries) to replace the standard 7-line boilerplate::
|
|
44
|
+
|
|
45
|
+
# Instead of:
|
|
46
|
+
BUNDLE_DIR = pathlib.Path(__file__).parent.parent
|
|
47
|
+
update_sys_path(os.fspath(BUNDLE_DIR / "tool"), "useBundled")
|
|
48
|
+
update_sys_path(
|
|
49
|
+
os.fspath(BUNDLE_DIR / "libs"),
|
|
50
|
+
os.getenv("LS_IMPORT_STRATEGY", "useBundled"),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Use:
|
|
54
|
+
from vscode_common_python_lsp import resolve_bundle_path
|
|
55
|
+
BUNDLE_DIR = resolve_bundle_path(__file__)
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
script_file:
|
|
60
|
+
The ``__file__`` of the calling script (expected to be at
|
|
61
|
+
``<bundle>/tool/lsp_server.py``).
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
str
|
|
66
|
+
The resolved bundle directory path (``<extension>/bundled/``),
|
|
67
|
+
for any further use by the caller.
|
|
68
|
+
"""
|
|
69
|
+
bundle_dir = pathlib.Path(script_file).parent.parent
|
|
70
|
+
bundle_str = os.fspath(bundle_dir)
|
|
71
|
+
|
|
72
|
+
# Always put the tool directory first (bundled server modules)
|
|
73
|
+
update_sys_path(os.fspath(bundle_dir / "tool"), "useBundled")
|
|
74
|
+
|
|
75
|
+
# Libs follow the LS_IMPORT_STRATEGY env var
|
|
76
|
+
update_sys_path(
|
|
77
|
+
os.fspath(bundle_dir / "libs"),
|
|
78
|
+
os.getenv("LS_IMPORT_STRATEGY", "useBundled"),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return bundle_str
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def update_environ_path() -> None:
|
|
85
|
+
"""Update PATH environment variable with the ``scripts`` directory.
|
|
86
|
+
|
|
87
|
+
Ensures tool executables installed in the virtual environment's scripts
|
|
88
|
+
directory (``Scripts`` on Windows, ``bin`` on Unix) are discoverable.
|
|
89
|
+
"""
|
|
90
|
+
scripts = sysconfig.get_path("scripts")
|
|
91
|
+
if not scripts:
|
|
92
|
+
return
|
|
93
|
+
for var_name in ("Path", "PATH"):
|
|
94
|
+
if var_name in os.environ:
|
|
95
|
+
paths = os.environ[var_name].split(os.pathsep)
|
|
96
|
+
if scripts not in paths:
|
|
97
|
+
paths.insert(0, scripts)
|
|
98
|
+
os.environ[var_name] = os.pathsep.join(paths)
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
|
|
37
102
|
def run_message_loop(
|
|
38
103
|
rpc: JsonRpc,
|
|
39
104
|
run_fn: Callable[..., object],
|
|
File without changes
|
|
File without changes
|
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/tests/test_code_actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/debug.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/paths.py
RENAMED
|
File without changes
|
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/runner.py
RENAMED
|
File without changes
|
{vscode_common_python_lsp-0.3.0 → vscode_common_python_lsp-0.5.0}/vscode_common_python_lsp/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|