@treedy/lsp-mcp 0.1.7 → 0.1.8
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.
- package/dist/bundled/pyright/dist/index.d.ts +2 -0
- package/dist/bundled/pyright/dist/index.js +1620 -0
- package/dist/bundled/pyright/dist/index.js.map +26 -0
- package/dist/bundled/pyright/dist/lsp/connection.d.ts +71 -0
- package/dist/bundled/pyright/dist/lsp/document-manager.d.ts +67 -0
- package/dist/bundled/pyright/dist/lsp/index.d.ts +3 -0
- package/dist/bundled/pyright/dist/lsp/types.d.ts +55 -0
- package/dist/bundled/pyright/dist/lsp-client.d.ts +55 -0
- package/dist/bundled/pyright/dist/tools/completions.d.ts +18 -0
- package/dist/bundled/pyright/dist/tools/definition.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/diagnostics.d.ts +12 -0
- package/dist/bundled/pyright/dist/tools/hover.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/references.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/rename.d.ts +18 -0
- package/dist/bundled/pyright/dist/tools/search.d.ts +20 -0
- package/dist/bundled/pyright/dist/tools/signature-help.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/status.d.ts +14 -0
- package/dist/bundled/pyright/dist/tools/symbols.d.ts +17 -0
- package/dist/bundled/pyright/dist/tools/update-document.d.ts +14 -0
- package/dist/bundled/pyright/dist/utils/position.d.ts +33 -0
- package/dist/bundled/pyright/package.json +54 -0
- package/dist/bundled/python/README.md +230 -0
- package/dist/bundled/python/pyproject.toml +61 -0
- package/dist/bundled/python/src/rope_mcp/__init__.py +3 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/config.cpython-312.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/config.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/pyright_client.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/rope_client.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/server.cpython-312.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/__pycache__/server.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/config.py +408 -0
- package/dist/bundled/python/src/rope_mcp/lsp/__init__.py +15 -0
- package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/client.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/types.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/lsp/client.py +624 -0
- package/dist/bundled/python/src/rope_mcp/lsp/types.py +82 -0
- package/dist/bundled/python/src/rope_mcp/pyright_client.py +147 -0
- package/dist/bundled/python/src/rope_mcp/rope_client.py +198 -0
- package/dist/bundled/python/src/rope_mcp/server.py +963 -0
- package/dist/bundled/python/src/rope_mcp/tools/__init__.py +26 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/change_signature.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/completions.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/definition.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/diagnostics.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/hover.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/move.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/references.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/rename.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/search.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/__pycache__/symbols.cpython-313.pyc +0 -0
- package/dist/bundled/python/src/rope_mcp/tools/change_signature.py +184 -0
- package/dist/bundled/python/src/rope_mcp/tools/completions.py +84 -0
- package/dist/bundled/python/src/rope_mcp/tools/definition.py +51 -0
- package/dist/bundled/python/src/rope_mcp/tools/diagnostics.py +18 -0
- package/dist/bundled/python/src/rope_mcp/tools/hover.py +49 -0
- package/dist/bundled/python/src/rope_mcp/tools/move.py +81 -0
- package/dist/bundled/python/src/rope_mcp/tools/references.py +60 -0
- package/dist/bundled/python/src/rope_mcp/tools/rename.py +61 -0
- package/dist/bundled/python/src/rope_mcp/tools/search.py +128 -0
- package/dist/bundled/python/src/rope_mcp/tools/symbols.py +118 -0
- package/dist/bundled/python/uv.lock +979 -0
- package/dist/bundled/typescript/dist/index.js +29534 -0
- package/dist/bundled/typescript/dist/index.js.map +211 -0
- package/dist/bundled/typescript/package.json +46 -0
- package/dist/bundled/vue/dist/index.d.ts +8 -0
- package/dist/bundled/vue/dist/index.js +21111 -0
- package/dist/bundled/vue/dist/ts-vue-service.d.ts +67 -0
- package/dist/bundled/vue/dist/vue-service.d.ts +144 -0
- package/dist/bundled/vue/package.json +45 -0
- package/dist/index.js +148 -58
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""Configuration for Python LSP MCP Server."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
import tomllib # type: ignore[import-not-found]
|
|
13
|
+
except ImportError:
|
|
14
|
+
import tomli as tomllib # type: ignore[import-not-found,import-untyped]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Backend(Enum):
|
|
18
|
+
"""Available backends for code analysis."""
|
|
19
|
+
|
|
20
|
+
ROPE = "rope"
|
|
21
|
+
PYRIGHT = "pyright"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Tools that support both backends
|
|
25
|
+
SHARED_TOOLS = {"hover", "definition", "references", "completions", "symbols"}
|
|
26
|
+
|
|
27
|
+
# Tools exclusive to each backend
|
|
28
|
+
ROPE_ONLY_TOOLS = {"rename"} # Rope has better refactoring
|
|
29
|
+
PYRIGHT_ONLY_TOOLS = {"diagnostics", "signature_help"} # Pyright exclusive
|
|
30
|
+
|
|
31
|
+
# Environment variable prefix (supports both old and new names)
|
|
32
|
+
ENV_PREFIXES = ["PYTHON_LSP_MCP_", "ROPE_MCP_"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class ServerConfig:
|
|
37
|
+
"""Configuration for the MCP server."""
|
|
38
|
+
|
|
39
|
+
# Default backend for shared features
|
|
40
|
+
default_backend: Backend = Backend.ROPE
|
|
41
|
+
|
|
42
|
+
# Per-tool backend overrides (None = use default)
|
|
43
|
+
tool_backends: dict[str, Backend] = field(default_factory=dict)
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_env(cls) -> "ServerConfig":
|
|
47
|
+
"""Create config from environment variables.
|
|
48
|
+
|
|
49
|
+
Environment variables (PYTHON_LSP_MCP_ or ROPE_MCP_ prefix):
|
|
50
|
+
*_BACKEND: Default backend (rope/pyright), default: rope
|
|
51
|
+
*_HOVER_BACKEND: Backend for hover (rope/pyright)
|
|
52
|
+
*_DEFINITION_BACKEND: Backend for definition
|
|
53
|
+
*_REFERENCES_BACKEND: Backend for references
|
|
54
|
+
*_COMPLETIONS_BACKEND: Backend for completions
|
|
55
|
+
*_SYMBOLS_BACKEND: Backend for symbols
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def get_env(suffix: str) -> Optional[str]:
|
|
59
|
+
"""Get environment variable with any prefix."""
|
|
60
|
+
for prefix in ENV_PREFIXES:
|
|
61
|
+
val = os.environ.get(f"{prefix}{suffix}", "").lower()
|
|
62
|
+
if val:
|
|
63
|
+
return val
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
default = get_env("BACKEND") or "rope"
|
|
67
|
+
default_backend = (
|
|
68
|
+
Backend(default) if default in ["rope", "pyright"] else Backend.ROPE
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
tool_backends = {}
|
|
72
|
+
for tool in SHARED_TOOLS:
|
|
73
|
+
val = get_env(f"{tool.upper()}_BACKEND")
|
|
74
|
+
if val in ["rope", "pyright"]:
|
|
75
|
+
tool_backends[tool] = Backend(val)
|
|
76
|
+
|
|
77
|
+
return cls(
|
|
78
|
+
default_backend=default_backend,
|
|
79
|
+
tool_backends=tool_backends,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def get_backend_for(self, tool: str) -> Backend:
|
|
83
|
+
"""Get the backend to use for a specific tool."""
|
|
84
|
+
if tool in ROPE_ONLY_TOOLS:
|
|
85
|
+
return Backend.ROPE
|
|
86
|
+
if tool in PYRIGHT_ONLY_TOOLS:
|
|
87
|
+
return Backend.PYRIGHT
|
|
88
|
+
|
|
89
|
+
if tool in self.tool_backends:
|
|
90
|
+
return self.tool_backends[tool]
|
|
91
|
+
return self.default_backend
|
|
92
|
+
|
|
93
|
+
def set_backend(self, backend: Backend, tool: Optional[str] = None) -> None:
|
|
94
|
+
"""Set the backend for a tool or as default.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
backend: The backend to use
|
|
98
|
+
tool: Optional tool name. If None, sets the default backend.
|
|
99
|
+
"""
|
|
100
|
+
if tool is None:
|
|
101
|
+
self.default_backend = backend
|
|
102
|
+
elif tool in SHARED_TOOLS:
|
|
103
|
+
self.tool_backends[tool] = backend
|
|
104
|
+
|
|
105
|
+
def set_all_backends(self, backend: Backend) -> None:
|
|
106
|
+
"""Set all shared tools to use the same backend."""
|
|
107
|
+
self.default_backend = backend
|
|
108
|
+
self.tool_backends.clear()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# Global config instance
|
|
112
|
+
_config: Optional[ServerConfig] = None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_config() -> ServerConfig:
|
|
116
|
+
"""Get the global server configuration."""
|
|
117
|
+
global _config
|
|
118
|
+
if _config is None:
|
|
119
|
+
_config = ServerConfig.from_env()
|
|
120
|
+
return _config
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def set_config(config: ServerConfig) -> None:
|
|
124
|
+
"""Set the global server configuration."""
|
|
125
|
+
global _config
|
|
126
|
+
_config = config
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ============================================================================
|
|
130
|
+
# Python Interpreter Path Configuration
|
|
131
|
+
# ============================================================================
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def find_pyright_python_path(workspace: str) -> Optional[str]:
|
|
135
|
+
"""Find Python path from Pyright configuration.
|
|
136
|
+
|
|
137
|
+
Checks in order:
|
|
138
|
+
1. pyrightconfig.json
|
|
139
|
+
2. pyproject.toml [tool.pyright]
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
workspace: The workspace root directory
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Python interpreter path if found, None otherwise
|
|
146
|
+
"""
|
|
147
|
+
workspace_path = Path(workspace)
|
|
148
|
+
|
|
149
|
+
# Check pyrightconfig.json
|
|
150
|
+
pyright_config = workspace_path / "pyrightconfig.json"
|
|
151
|
+
if pyright_config.exists():
|
|
152
|
+
try:
|
|
153
|
+
with open(pyright_config, "r", encoding="utf-8") as f:
|
|
154
|
+
config = json.load(f)
|
|
155
|
+
python_path = _extract_python_path_from_pyright(config, workspace_path)
|
|
156
|
+
if python_path:
|
|
157
|
+
return python_path
|
|
158
|
+
except (json.JSONDecodeError, OSError):
|
|
159
|
+
pass
|
|
160
|
+
|
|
161
|
+
# Check pyproject.toml
|
|
162
|
+
pyproject = workspace_path / "pyproject.toml"
|
|
163
|
+
if pyproject.exists():
|
|
164
|
+
try:
|
|
165
|
+
with open(pyproject, "rb") as f:
|
|
166
|
+
config = tomllib.load(f)
|
|
167
|
+
pyright_config = config.get("tool", {}).get("pyright", {})
|
|
168
|
+
python_path = _extract_python_path_from_pyright(
|
|
169
|
+
pyright_config, workspace_path
|
|
170
|
+
)
|
|
171
|
+
if python_path:
|
|
172
|
+
return python_path
|
|
173
|
+
except (tomllib.TOMLDecodeError, OSError):
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _extract_python_path_from_pyright(
|
|
180
|
+
config: dict, workspace_path: Path
|
|
181
|
+
) -> Optional[str]:
|
|
182
|
+
"""Extract Python path from Pyright config dict.
|
|
183
|
+
|
|
184
|
+
Supports:
|
|
185
|
+
- pythonPath: direct path to Python interpreter
|
|
186
|
+
- venvPath + venv: virtual environment path
|
|
187
|
+
"""
|
|
188
|
+
# Direct pythonPath
|
|
189
|
+
if "pythonPath" in config:
|
|
190
|
+
python_path = Path(config["pythonPath"])
|
|
191
|
+
if not python_path.is_absolute():
|
|
192
|
+
python_path = workspace_path / python_path
|
|
193
|
+
if python_path.exists():
|
|
194
|
+
return str(python_path)
|
|
195
|
+
|
|
196
|
+
# venvPath + venv combination
|
|
197
|
+
venv_path = config.get("venvPath")
|
|
198
|
+
venv_name = config.get("venv")
|
|
199
|
+
if venv_path and venv_name:
|
|
200
|
+
venv_dir = Path(venv_path)
|
|
201
|
+
if not venv_dir.is_absolute():
|
|
202
|
+
venv_dir = workspace_path / venv_dir
|
|
203
|
+
venv_dir = venv_dir / venv_name
|
|
204
|
+
|
|
205
|
+
# Check for Python executable
|
|
206
|
+
if sys.platform == "win32":
|
|
207
|
+
python_exe = venv_dir / "Scripts" / "python.exe"
|
|
208
|
+
else:
|
|
209
|
+
python_exe = venv_dir / "bin" / "python"
|
|
210
|
+
|
|
211
|
+
if python_exe.exists():
|
|
212
|
+
return str(python_exe)
|
|
213
|
+
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def find_venv_python_path(workspace: str) -> Optional[str]:
|
|
218
|
+
"""Find Python path from common virtual environment locations.
|
|
219
|
+
|
|
220
|
+
Checks:
|
|
221
|
+
- .venv/bin/python
|
|
222
|
+
- venv/bin/python
|
|
223
|
+
- env/bin/python
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
workspace: The workspace root directory
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Python interpreter path if found, None otherwise
|
|
230
|
+
"""
|
|
231
|
+
workspace_path = Path(workspace)
|
|
232
|
+
venv_dirs = [".venv", "venv", "env"]
|
|
233
|
+
|
|
234
|
+
for venv_dir in venv_dirs:
|
|
235
|
+
if sys.platform == "win32":
|
|
236
|
+
python_exe = workspace_path / venv_dir / "Scripts" / "python.exe"
|
|
237
|
+
else:
|
|
238
|
+
python_exe = workspace_path / venv_dir / "bin" / "python"
|
|
239
|
+
|
|
240
|
+
if python_exe.exists():
|
|
241
|
+
return str(python_exe)
|
|
242
|
+
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def get_python_path_for_workspace(workspace: str) -> str:
|
|
247
|
+
"""Get the Python interpreter path for a workspace.
|
|
248
|
+
|
|
249
|
+
Priority:
|
|
250
|
+
1. Manually set path (via set_python_path tool)
|
|
251
|
+
2. Pyright configuration (pyrightconfig.json or pyproject.toml)
|
|
252
|
+
3. Virtual environment in workspace (.venv, venv, env)
|
|
253
|
+
4. Current Python interpreter (sys.executable)
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
workspace: The workspace root directory
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Path to Python interpreter
|
|
260
|
+
"""
|
|
261
|
+
workspace = os.path.abspath(workspace)
|
|
262
|
+
|
|
263
|
+
# Check manually set path
|
|
264
|
+
if workspace in _python_paths:
|
|
265
|
+
return _python_paths[workspace]
|
|
266
|
+
|
|
267
|
+
# Check global override
|
|
268
|
+
if _global_python_path:
|
|
269
|
+
return _global_python_path
|
|
270
|
+
|
|
271
|
+
# Check Pyright config
|
|
272
|
+
pyright_path = find_pyright_python_path(workspace)
|
|
273
|
+
if pyright_path:
|
|
274
|
+
return pyright_path
|
|
275
|
+
|
|
276
|
+
# Check virtual environment
|
|
277
|
+
venv_path = find_venv_python_path(workspace)
|
|
278
|
+
if venv_path:
|
|
279
|
+
return venv_path
|
|
280
|
+
|
|
281
|
+
# Fall back to current interpreter
|
|
282
|
+
return sys.executable
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# Per-workspace Python paths (set via tool)
|
|
286
|
+
_python_paths: dict[str, str] = {}
|
|
287
|
+
|
|
288
|
+
# Global Python path override
|
|
289
|
+
_global_python_path: Optional[str] = None
|
|
290
|
+
|
|
291
|
+
# Active workspace for single-project mode
|
|
292
|
+
_active_workspace: Optional[str] = None
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def set_active_workspace(workspace: str) -> str:
|
|
296
|
+
"""Set the active workspace.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
workspace: Path to the workspace root
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
The absolute path to the active workspace
|
|
303
|
+
"""
|
|
304
|
+
global _active_workspace
|
|
305
|
+
_active_workspace = os.path.abspath(workspace)
|
|
306
|
+
return _active_workspace
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def get_active_workspace() -> Optional[str]:
|
|
310
|
+
"""Get the currently active workspace."""
|
|
311
|
+
return _active_workspace
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def is_file_in_workspace(file_path: str) -> bool:
|
|
315
|
+
"""Check if a file belongs to the active workspace.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
file_path: Path to the file
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
True if the file is within the active workspace, False otherwise.
|
|
322
|
+
Returns True if no active workspace is set (backward compatibility).
|
|
323
|
+
"""
|
|
324
|
+
if not _active_workspace:
|
|
325
|
+
return True
|
|
326
|
+
|
|
327
|
+
abs_file = os.path.abspath(file_path)
|
|
328
|
+
return abs_file.startswith(_active_workspace)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def validate_file_workspace(file_path: str) -> Optional[dict]:
|
|
332
|
+
"""Validate that a file is within the active workspace.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
file_path: Path to the file
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Error dict if file is outside workspace, None otherwise.
|
|
339
|
+
"""
|
|
340
|
+
if not is_file_in_workspace(file_path):
|
|
341
|
+
return {
|
|
342
|
+
"error": "Context Mismatch",
|
|
343
|
+
"message": (
|
|
344
|
+
f"The file '{file_path}' is outside the active workspace '{_active_workspace}'.\n\n"
|
|
345
|
+
"Current Logic:\n"
|
|
346
|
+
"1. I only analyze files from the active project to ensure accuracy and save resources.\n"
|
|
347
|
+
"2. You must explicitly switch the workspace if you want to work on a different project.\n\n"
|
|
348
|
+
"Action Required:\n"
|
|
349
|
+
"Please call 'switch_workspace(path=\"...\")' with the new project root before retrying."
|
|
350
|
+
),
|
|
351
|
+
"current_workspace": _active_workspace,
|
|
352
|
+
}
|
|
353
|
+
return None
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def set_python_path(python_path: str, workspace: Optional[str] = None) -> dict:
|
|
357
|
+
"""Set the Python interpreter path.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
python_path: Path to Python interpreter
|
|
361
|
+
workspace: Optional workspace to set path for.
|
|
362
|
+
If None, sets global default.
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Dict with success status and message
|
|
366
|
+
"""
|
|
367
|
+
global _global_python_path
|
|
368
|
+
|
|
369
|
+
# Validate the path exists
|
|
370
|
+
path = Path(python_path)
|
|
371
|
+
if not path.exists():
|
|
372
|
+
return {
|
|
373
|
+
"success": False,
|
|
374
|
+
"error": f"Python path does not exist: {python_path}",
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
# Check if it's executable
|
|
378
|
+
if not os.access(python_path, os.X_OK):
|
|
379
|
+
return {
|
|
380
|
+
"success": False,
|
|
381
|
+
"error": f"Python path is not executable: {python_path}",
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if workspace:
|
|
385
|
+
workspace = os.path.abspath(workspace)
|
|
386
|
+
_python_paths[workspace] = python_path
|
|
387
|
+
return {
|
|
388
|
+
"success": True,
|
|
389
|
+
"message": f"Python path set for workspace: {workspace}",
|
|
390
|
+
"python_path": python_path,
|
|
391
|
+
"workspace": workspace,
|
|
392
|
+
}
|
|
393
|
+
else:
|
|
394
|
+
_global_python_path = python_path
|
|
395
|
+
return {
|
|
396
|
+
"success": True,
|
|
397
|
+
"message": "Global Python path set",
|
|
398
|
+
"python_path": python_path,
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def get_python_path_status() -> dict:
|
|
403
|
+
"""Get the current Python path configuration status."""
|
|
404
|
+
return {
|
|
405
|
+
"global_python_path": _global_python_path,
|
|
406
|
+
"workspace_python_paths": dict(_python_paths),
|
|
407
|
+
"current_interpreter": sys.executable,
|
|
408
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""LSP client for Pyright language server."""
|
|
2
|
+
|
|
3
|
+
from .client import LspClient, get_lsp_client, close_all_clients, refresh_lsp_documents
|
|
4
|
+
from .types import Position, Range, Location, TextDocumentIdentifier
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"LspClient",
|
|
8
|
+
"get_lsp_client",
|
|
9
|
+
"close_all_clients",
|
|
10
|
+
"refresh_lsp_documents",
|
|
11
|
+
"Position",
|
|
12
|
+
"Range",
|
|
13
|
+
"Location",
|
|
14
|
+
"TextDocumentIdentifier",
|
|
15
|
+
]
|