Files
netdisk-fast-download/parser/doc/PYLSP_WEBSOCKET_GUIDE.md
q 2fcf9cfab1 docs: 更新文档导航和解析器指南
- 添加演练场(Playground)文档导航区到主 README
- 新增 Python 解析器文档链接(开发指南、测试报告、LSP集成)
- 更新前端版本号至 0.1.9b19p
- 补充 Python 解析器 requests 库使用章节和官方文档链接
- 添加 JavaScript 和 Python 解析器的语言版本和官方文档
- 优化文档结构,分类为项目文档和外部资源
2026-01-11 22:35:45 +08:00

7.3 KiB
Raw Blame History

Python Playground pylsp WebSocket 集成指南

概述

本文档说明了如何将 jedi 的 pylsp (python-lsp-server) 通过 WebSocket 集成到 Python Playground 中,实现实时代码检查、自动完成和悬停提示等功能。

架构

┌─────────────────────────────────────────────────────────────┐
│                     前端 (Vue + Monaco)                      │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  PylspClient.js                                         ││
│  │  - 通过 WebSocket 发送 LSP JSON-RPC 消息                 ││
│  │  - 接收诊断信息并转换为 Monaco markers                   ││
│  └─────────────────────────────────────────────────────────┘│
└──────────────────────────┬──────────────────────────────────┘
                           │ WebSocket (SockJS)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│               后端 (Vert.x + SockJS)                         │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  PylspWebSocketHandler.java                             ││
│  │  - @SockRouteMapper("/pylsp/")                          ││
│  │  - 管理 pylsp 子进程                                     ││
│  │  - 转发 LSP 消息                                         ││
│  └─────────────────────────────────────────────────────────┘│
└──────────────────────────┬──────────────────────────────────┘
                           │ stdio (LSP协议)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                pylsp (python-lsp-server)                    │
│  - jedi: 代码补全、定义跳转                                  │
│  - pyflakes: 语法错误检查                                    │
│  - pycodestyle: PEP8 风格检查                               │
│  - mccabe: 复杂度检查                                       │
└─────────────────────────────────────────────────────────────┘

文件清单

后端 (Java)

  1. PylspWebSocketHandler.java
    • 路径: web-service/src/main/java/cn/qaiu/lz/web/controller/PylspWebSocketHandler.java
    • 功能: WebSocket 端点,桥接前端与 pylsp 子进程
    • 端点: /ws/pylsp/*

前端 (JavaScript/Vue)

  1. pylspClient.js
    • 路径: web-front/src/utils/pylspClient.js
    • 功能: LSP WebSocket 客户端,封装 LSP 协议

测试

  1. RequestsIntegrationTest.java

    • 路径: web-service/src/test/java/cn/qaiu/lz/web/playground/RequestsIntegrationTest.java
    • 功能: requests 库集成测试
  2. test_playground_api.py

    • 路径: web-service/src/test/python/test_playground_api.py
    • 功能: API 接口的 pytest 测试脚本

使用方法

1. 安装 pylsp

pip install python-lsp-server[all]

或者只安装核心功能:

pip install python-lsp-server jedi

2. 前端集成示例

import PylspClient from '@/utils/pylspClient';

// 创建客户端
const pylsp = new PylspClient({
  onDiagnostics: (uri, markers) => {
    // 设置 Monaco Editor markers
    monaco.editor.setModelMarkers(model, 'pylsp', markers);
  },
  onConnected: () => {
    console.log('pylsp 已连接');
  },
  onError: (error) => {
    console.error('pylsp 错误:', error);
  }
});

// 连接
await pylsp.connect();

// 打开文档
pylsp.openDocument(pythonCode);

// 更新文档(当代码改变时)
pylsp.updateDocument(newCode);

// 获取补全
const completions = await pylsp.getCompletions(line, column);

// 获取悬停信息
const hover = await pylsp.getHover(line, column);

// 断开连接
pylsp.disconnect();

3. 与 Monaco Editor 集成

// 监听代码变化
editor.onDidChangeModelContent((e) => {
  const content = editor.getValue();
  pylsp.updateDocument(content);
});

// 注册补全提供者
monaco.languages.registerCompletionItemProvider('python', {
  provideCompletionItems: async (model, position) => {
    const items = await pylsp.getCompletions(
      position.lineNumber - 1,
      position.column - 1
    );
    return { suggestions: items.map(convertToMonacoItem) };
  }
});

已知限制

GraalPy requests 库限制

由于 GraalPy 的 unicodedata/LLVM 限制,requests 库在后续创建的 Context 中无法正常导入(会抛出 PolyglotException: null)。

错误链

requests → encodings.idna → stringprep → from unicodedata import ucd_3_2_0

解决方案

  1. 在代码顶层导入 requests不要在函数内部导入
  2. 使用标准库的 urllib.request 作为替代
  3. 首次执行时预热 requests 导入

测试注意事项

  1. PyPlaygroundFullTest 中的测试2和测试5被标记为跳过已知限制
  2. 测试13前端模板代码使用不依赖 requests 的版本
  3. requests 功能在实际运行时通过首个 Context 可以正常使用

测试命令

运行 Java 单元测试

# PyPlaygroundFullTest (13 个测试)
cd parser && mvn exec:java \
  -Dexec.mainClass="cn.qaiu.parser.custompy.PyPlaygroundFullTest" \
  -Dexec.classpathScope=test -q

# RequestsIntegrationTest
cd web-service && mvn exec:java \
  -Dexec.mainClass="cn.qaiu.lz.web.playground.RequestsIntegrationTest" \
  -Dexec.classpathScope=test -q

运行 Python API 测试

# 需要后端服务运行
cd web-service/src/test/python
pip install pytest requests
pytest test_playground_api.py -v

配置

后端配置

PylspWebSocketHandler.java 中可以配置:

  • pylsp 启动命令
  • 心跳间隔
  • 进程超时

前端配置

pylspClient.js 中可以配置:

  • WebSocket URL
  • 重连次数
  • 重连延迟
  • 请求超时

安全考虑

  1. pylsp 进程在沙箱环境中运行
  2. 每个 WebSocket 连接对应一个独立的 pylsp 进程
  3. 连接关闭时自动清理进程
  4. Playground 访问需要认证(如果配置了密码)

未来改进

  1. 支持多文件项目分析
  2. 添加 pyright 类型检查
  3. 支持代码格式化black/autopep8
  4. 添加重构功能
  5. 支持虚拟环境选择