You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程方式调用Pylance查找代码引用及定义位置?

如何通过编程调用Pylance查找代码引用?

已知Pylance作为语言服务器,理论上可通过连接它提取函数调用的引用信息。比如以下代码中,check_files_in_directory是从GPT4Readability.utils模块导入的,但无法直接通过常规方式确认其定义位置,希望了解如何通过编程调用Pylance来获取这类信息:

import os
from getpass import getpass
from GPT4Readability.utils import *
import importlib.resources as pkg_resources  


def generate_readme(root_dir, output_name, model):
    """Generates a README.md file based on the python files in the provided directory

    Args:
        root_dir (str): The root directory of the python package to parse and generate a readme for
    """

    # prompt_folder_name = os.path.join(os.path.dirname(__file__), "prompts")
    # prompt_path = os.path.join(prompt_folder_name, "readme_prompt.txt")

    with pkg_resources.open_text('GPT4Readability.prompts','readme_prompt.txt') as f:         
        inb_msg = f.read()

    # with open(prompt_path) as f:
    #     lines = f.readlines()
    # inb_msg = "".join(lines)

    file_check_result = check_files_in_directory(root_dir)

实现方法

  • 基于语言服务器协议(LSP)与Pylance通信
    Pylance完全遵循LSP规范,你可以通过实现轻量LSP客户端,调用LSP的textDocument/definition请求来获取符号的定义位置,这正是你需要的函数来源信息。

  • 核心步骤拆解

    1. 启动Pylance进程:找到Pylance的JS服务器文件(通常在VS Code扩展目录,路径类似~/.vscode/extensions/ms-python.vscode-pylance-*/dist/server.bundle.js),通过Node.js启动它,用标准输入输出做通信通道。
    2. 初始化LSP会话:发送初始化请求,传入项目根目录、进程ID等信息,让Pylance加载目标代码所在的项目环境。
    3. 告知Pylance目标文档内容:通过textDocument/didOpen通知,把要分析的代码内容传递给Pylance。
    4. 发送定义查询请求:针对check_files_in_directory调用的位置(行号、列号,注意LSP行号从0开始),发送textDocument/definition请求。
    5. 解析响应:Pylance会返回该函数的定义文件URI、行号等信息,直接就能确认它是否来自GPT4Readability.utils模块。
  • 简化代码示例
    以下是用Python+asyncio实现的核心逻辑:

    import asyncio
    import json
    import os
    
    async def get_symbol_definition():
        # 替换为你的Pylance服务器路径
        pylance_path = "/path/to/ms-python.vscode-pylance-*/dist/server.bundle.js"
        proc = await asyncio.create_subprocess_exec(
            "node", pylance_path,
            stdin=asyncio.subprocess.PIPE,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
    
        # 发送初始化请求
        init_req = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "initialize",
            "params": {
                "processId": os.getpid(),
                "rootUri": "file:///path/to/your/project/root",
                "capabilities": {}
            }
        }
        await proc.stdin.write(json.dumps(init_req).encode() + b"\r\n")
        await proc.stdin.drain()
        # 读取初始化响应(可忽略内容,确认会话建立即可)
        await proc.stdout.readline()
    
        # 传递目标代码文档
        target_code = """import os
    from getpass import getpass
    from GPT4Readability.utils import *
    import importlib.resources as pkg_resources  
    
    def generate_readme(root_dir, output_name, model):
        with pkg_resources.open_text('GPT4Readability.prompts','readme_prompt.txt') as f:         
            inb_msg = f.read()
        file_check_result = check_files_in_directory(root_dir)"""
        did_open = {
            "jsonrpc": "2.0",
            "method": "textDocument/didOpen",
            "params": {
                "textDocument": {
                    "uri": "file:///path/to/your/target/file.py",
                    "languageId": "python",
                    "version": 1,
                    "text": target_code
                }
            }
        }
        await proc.stdin.write(json.dumps(did_open).encode() + b"\r\n")
        await proc.stdin.drain()
    
        # 查询check_files_in_directory的定义(对应代码中第12行的调用,LSP行号为11)
        def_req = {
            "jsonrpc": "2.0",
            "id": 2,
            "method": "textDocument/definition",
            "params": {
                "textDocument": {"uri": "file:///path/to/your/target/file.py"},
                "position": {"line": 11, "character": 27}
            }
        }
        await proc.stdin.write(json.dumps(def_req).encode() + b"\r\n")
        await proc.stdin.drain()
    
        # 解析响应结果
        res_line = await proc.stdout.readline()
        res_data = json.loads(res_line.decode())
        if "result" in res_data and len(res_data["result"]) > 0:
            def_uri = res_data["result"][0]["uri"]
            def_line = res_data["result"][0]["range"]["start"]["line"]
            print(f"函数定义位置:{def_uri},行号:{def_line + 1}")
    
        # 关闭会话
        shutdown_req = {"jsonrpc": "2.0", "id": 3, "method": "shutdown"}
        await proc.stdin.write(json.dumps(shutdown_req).encode() + b"\r\n")
        await proc.stdin.drain()
        await proc.stdin.write(b"exit\r\n")
        await proc.wait()
    
    asyncio.run(get_symbol_definition())
    
  • 注意事项

    • 确保Pylance路径正确,不同系统、VS Code版本的扩展路径有差异。
    • 若项目有虚拟环境或特殊依赖,可在初始化请求的workspaceConfiguration参数中指定Python解释器路径,保证Pylance能正确解析依赖。
    • LSP交互严格遵循JSON-RPC格式,请求ID需唯一,参数格式不能出错,否则Pylance会返回错误响应。

内容的提问来源于stack exchange,提问作者Exploring

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:37:23