跳转到主要内容

查找指定符号的Python代码

项目描述

symboex

PyPI Changelog Tests License

查找指定符号的Python代码

阅读symboex:搜索Python中的函数和类,然后将它们导入到LLM中以获取此项目的背景信息。

安装

使用pip安装此工具

pip install symbex

或使用Homebrew

brew install simonw/llm/symbex

使用方法

symboex可以搜索Python文件顶层出现的函数和类名。

要搜索当前目录及其所有子目录中的每个.py文件,请按如下方式运行

symbex my_function

您可以同时搜索多个符号

symbex my_function MyClass

支持通配符 - 要搜索每个test_函数,请运行此命令(注意单引号,以防止shell将*解释为通配符)

symbex 'test_*'

要搜索类中的方法,使用class.method表示法

symbex Entry.get_absolute_url

这里也支持通配符

symbex 'Entry.*'
symbex '*.get_absolute_url'
symbex '*.get_*'

或者要查看每个类的每个方法

symbex '*.*'

要搜索特定文件,请使用-f选项传递该文件。您可以通过多次传递此选项来搜索多个文件。

symbex MyClass -f my_file.py

要搜索特定目录及其所有子目录,请使用-d/--directory选项

symbex Database -d ~/projects/datasette

如果您知道要检查的模块可以由Python导入,则可以使用-m/--module name选项。以下示例显示了asyncio包中每个符号的签名

symbex -m asyncio -s --imports

您可以使用--stdlib搜索包含Python标准库的目录。这可以用于快速查找特定Python库函数的源代码

symbex --stdlib -in to_thread

-in 的解释如下。如果您提供了 --stdlib 但没有提供任何 -d-f 选项,则 --silent 将自动开启,因为标准库否则会产生许多不同的警告。

输出开始如下

# from asyncio.threads import to_thread
async def to_thread(func, /, *args, **kwargs):
    """Asynchronously run function *func* in a separate thread.
    # ...

您可以使用 -x/--exclude 选项排除指定目录中的文件

symbex Database -d ~/projects/datasette -x ~/projects/datasette/tests

如果 symbex 遇到它无法解析的任何 Python 代码,它将打印一条警告消息并继续搜索

# Syntax error in path/badcode.py: expected ':' (<unknown>, line 1)

通过传递 --silent 来抑制这些警告

symbex MyClass --silent

过滤器

除了搜索符号之外,您还可以将过滤器应用于结果。

以下过滤器可用:

  • --function - 仅函数
  • --class - 仅类
  • --async - 仅 async def 函数
  • --unasync - 仅非异步函数
  • --documented - 拥有文档字符串的函数/类
  • --undocumented - 没有文档字符串的函数/类
  • --public - 公共函数/类 - 没有前缀 _name(或为 __*__ 方法)
  • --private - 私有函数/类 - 有前缀 _name 并且不是 __*__
  • --dunder - 匹配 __*__ 的函数 - 通常应与 *.* 一起使用以找到所有 dunder 方法
  • --typed - 至少有一个类型注解的函数
  • --untyped - 没有类型注解的函数
  • --partially-typed - 拥有一些类型注解但不是所有的函数
  • --fully-typed - 对于每个参数和返回值都有类型注解的函数
  • --no-init - 排除 __init__(self) 方法。当与 --fully-typed '*.*' 结合使用时很有用,以避免返回作为完全类型化的分类的 __init__(self) 方法,因为 __init__ 不需要参数或返回类型注解。

例如,要查看项目中每个没有类型注解的 async def 函数的签名

symbex -s --async --untyped

对于类方法,而不是函数,您可以将过滤器与符号搜索参数 *.* 结合使用。

此示例显示了每个具有所有参数和返回值类型注解的 Python 标准库类方法的完整源代码

symbex --fully-typed --no-init '*.*' --stdlib

要找到所有公共函数和方法,它们缺乏文档,仅显示每个函数的签名

symbex '*' '*.*' --public --undocumented --signatures

示例输出

在一个新的 Datasette 检出中,我运行了这个命令

symbex MessagesDebugView get_long_description

这是命令的输出

# File: setup.py Line: 5
def get_long_description():
    with open(
        os.path.join(os.path.dirname(os.path.abspath(__file__)), "README.md"),
        encoding="utf8",
    ) as fp:
        return fp.read()

# File: datasette/views/special.py Line: 60
class PatternPortfolioView(View):
    async def get(self, request, datasette):
        await datasette.ensure_permissions(request.actor, ["view-instance"])
        return Response.html(
            await datasette.render_template(
                "patterns.html",
                request=request,
                view_name="patterns",
            )
        )

仅签名

-s/--signatures 选项将列出函数和类的签名,例如

symbex -s -f symbex/lib.py
# File: symbex/lib.py Line: 107
def function_definition(function_node: AST):

# File: symbex/lib.py Line: 13
def find_symbol_nodes(code: str, filename: str, symbols: Iterable[str]) -> List[Tuple[(AST, Optional[str])]]:

# File: symbex/lib.py Line: 175
def class_definition(class_def):

# File: symbex/lib.py Line: 209
def annotation_definition(annotation: AST) -> str:

# File: symbex/lib.py Line: 227
def read_file(path):

# File: symbex/lib.py Line: 253
class TypeSummary:

# File: symbex/lib.py Line: 258
def type_summary(node: AST) -> Optional[TypeSummary]:

# File: symbex/lib.py Line: 304
def quoted_string(s):

# File: symbex/lib.py Line: 315
def import_line_for_function(function_name: str, filepath: str, possible_root_dirs: List[str]) -> str:

# File: symbex/lib.py Line: 37
def code_for_node(code: str, node: AST, class_name: str, signatures: bool, docstrings: bool) -> Tuple[(str, int)]:

# File: symbex/lib.py Line: 71
def add_docstring(definition: str, node: AST, docstrings: bool, is_method: bool) -> str:

# File: symbex/lib.py Line: 82
def match(name: str, symbols: Iterable[str]) -> bool:

这可以与其他选项结合使用,或者您可以直接运行 symbex -s 以查看当前目录及其子目录中的每个符号。

要包括估计的导入路径,如 # from symbex.lib import match,请使用 --imports。这些将相对于您指定的目录进行计算,或者您可以传递一个或多个 --sys-path 选项以请求相对于这些目录进行导入计算,就像它们位于 sys.path 一样。

~/dev/symbex/symbex match --imports -s --sys-path ~/dev/symbex

示例输出

# File: symbex/lib.py Line: 82
# from symbex.lib import match
def match(name: str, symbols: Iterable[str]) -> bool:

要抑制 # File: ... 注释,请使用 --no-file-n

因此,要同时显示导入路径并抑制文件注释,请使用 -in 作为快捷方式。

symbex -in match

输出

# from symbex.lib import match
def match(name: str, symbols: Iterable[str]) -> bool:

要包括签名中的文档字符串,请使用 --docstrings

symbex match --docstrings -f symbex/lib.py

示例输出

# File: symbex/lib.py Line: 82
def match(name: str, symbols: Iterable[str]) -> bool:
    "Returns True if name matches any of the symbols, resolving wildcards"

计数符号

如果您只想计数与您的过滤器匹配的函数和类的数量,请使用 --count 选项。以下是如何计数您的类

symbex --class --count

或者计数每个异步测试函数

symbex --async 'test_*' --count

结构化输出

LLM 默认输出纯文本(实际上是有效的 Python 代码,多亏了它使用注释的方式)。

您可以使用以下选项请求输出 CSV、TSV、JSON 或每行换行符分隔的 JSON:

  • --json:JSON 数组,例如 [{"id": "...", "code": "..."}]
  • --nl:每行换行符分隔的 JSON,例如 {"id": "...", "code": "..."} 每行一个
  • --csv:CSV,以 id,code 作为标题行
  • --tsv:TSV,以 id\tcode 作为标题行

在每种情况下,ID 都将是包含符号的文件路径,后跟一个冒号,然后是符号的行号,例如

{
  "id": "symbex/lib.py:82",
  "code": "def match(name: str, symbols: Iterable[str]) -> bool:"
}

如果您传递 -i/--imports,则 ID 将是导入行

{
  "id": "from symbex.lib import match",
  "code": "def match(name: str, symbols: Iterable[str]) -> bool:"
}

传递 --id-prefix 'something:' 以在 ID 的开头添加指定的前缀。

以下示例将生成包含所有测试函数的 CSV 文件,使用导入样式的 ID 和前缀 test:

symbex 'test_*' \
  --function \
  --imports \
  --csv > tests.csv

与 LLM 一起使用

此工具主要是为与 LLM 一起使用而设计的,LLM 是一个用于处理大型语言模型的 CLI 工具。

symbex 可以轻松获取特定的类或函数并将其传递给 llm 命令。

例如,我在 Datasette 仓库根目录下运行了以下命令

symbex Response | llm --system 'Explain this code, succinctly'

并得到了以下结果

此代码定义了一个自定义的 Response 类,其中包含用于返回 HTTP 响应的方法。它包括设置 cookies、返回 HTML、文本和 JSON 响应以及重定向到不同 URL 的方法。`asgi_send` 方法使用 ASGI(异步服务器网关接口)协议将响应发送到客户端。

结构化输出功能旨在与 LLM 嵌入 一起使用。您可以使用 llm embed-multi 生成代码库中每个符号的嵌入,如下所示

symbex '*' '*:*' --nl | \
  llm embed-multi symbols - \
  --format nl --database embeddings.db --store

这将创建一个名为 embeddings.db 的数据库,其中包含您的所有符号以及嵌入向量。

然后您可以像这样搜索您的代码

llm similar symbols -d embeddings.db -c 'test csv' | jq

替换匹配的符号

可以使用 --replace 选项使用标准输入的内容替换单个匹配符号。

给定一个名为 my_code.py 的文件,其内容如下

def first_function():
    # This will be ignored
    pass

def second_function():
    # This will be replaced
    pass

运行以下命令

echo "def second_function(a, b):
    # This is a replacement implementation
    return a + b + 3
" | symbex second_function --replace

结果将是更新后的 my_code.py,其中包含以下内容

def first_function():
    # This will be ignored
    pass

def second_function(a, b):
    # This is a replacement implementation
    return a + b + 3

应谨慎使用此功能!我建议仅对已提交到 Git 的代码使用此功能,这样您可以使用 git diff 查看它所做的更改,并使用 git checkout my_code.py 进行撤销。

通过运行命令替换匹配的符号

可以使用 --rexec COMMAND 选项通过运行命令并使用其输出替换单个匹配符号。

该命令将使用匹配符号的定义作为其标准输入运行。该命令的输出将用作替换文本。

以下示例使用 sed 在每个匹配行的开头添加 #,从而注释掉匹配的功能

symbex first_function --rexec "sed 's/^/# /'"

这将就地修改第一个函数,使其看起来像这样

# def first_function():
#    # This will be ignored
#    pass

一个更令人兴奋的示例使用 LLM。此示例将使用 gpt-3.5-turbo 模型添加类型提示并生成文档字符串

symbex second_function \
  --rexec "llm --system 'add type hints and a docstring'"

我对此代码运行了以下命令

def first_function():
    # This will be ignored
    pass

def second_function(a, b):
    return a + b + 3

第二个函数就地更新为以下内容

def second_function(a: int, b: int) -> int:
    """
    Returns the sum of two integers (a and b) plus 3.

    Parameters:
    a (int): The first integer.
    b (int): The second integer.

    Returns:
    int: The sum of a and b plus 3.
    """
    return a + b + 3

在 CI 中使用

--check 选项会导致 symbex 在找到任何查询匹配项时返回非零退出代码。

您可以在CI中使用此功能来防止未添加文档的公共函数被添加。

symbex --function --public --undocumented --check

如果有任何未文档化的函数,此功能将静默失败,但会设置退出代码1

将此作为GitHub Actions等CI工具的步骤应导致测试失败。

运行此命令以查看上一个命令的退出代码。

echo $?

--check默认情况下不会输出任何内容。添加--count以输出匹配符号的计数,或添加-s/--signatures以输出匹配符号的签名,例如

symbex --function --public --undocumented --check --count

类似工具

  • pyastgrep由Luke Plant提供,它提供了使用XPath查看和搜索Python AST的高级功能。
  • cq是一个工具,允许您“使用类似CSS的选择器提取代码片段”,它使用Tree-sitter构建,主要针对JavaScript和TypeScript。

symbex --help

Usage: symbex [OPTIONS] [SYMBOLS]...

  Find symbols in Python code and print the code for them.

  Example usage:

      # Search current directory and subdirectories
      symbex my_function MyClass

      # Search using a wildcard
      symbex 'test_*'

      # Find a specific class method
      symbex 'MyClass.my_method'

      # Find class methods using wildcards
      symbex '*View.handle_*'

      # Search a specific file
      symbex MyClass -f my_file.py

      # Search within a specific directory and its subdirectories
      symbex Database -d ~/projects/datasette

      # View signatures for all symbols in current directory and subdirectories
      symbex -s

      # View signatures for all test functions
      symbex 'test_*' -s

      # View signatures for all async functions with type definitions
      symbex --async --typed -s

      # Count the number of --async functions in the project
      symbex --async --count

      # Replace my_function with a new implementation:
      echo "def my_function(a, b):
          # This is a replacement implementation
          return a + b + 3
      " | symbex my_function --replace

      # Replace my_function with the output of a command:
      symbex first_function --rexec "sed 's/^/# /'"
      # This uses sed to comment out the function body

Options:
  --version                  Show the version and exit.
  -f, --file FILE            Files to search
  -d, --directory DIRECTORY  Directories to search
  --stdlib                   Search the Python standard library
  -x, --exclude DIRECTORY    Directories to exclude
  -s, --signatures           Show just function and class signatures
  -n, --no-file              Don't include the # File: comments in the output
  -i, --imports              Show 'from x import y' lines for imported symbols
  -m, --module TEXT          Modules to search within
  --sys-path TEXT            Calculate imports relative to these on sys.path
  --docs, --docstrings       Show function and class signatures plus docstrings
  --count                    Show count of matching symbols
  --silent                   Silently ignore Python files with parse errors
  --function                 Filter functions
  --async                    Filter async functions
  --unasync                  Filter non-async functions
  --class                    Filter classes
  --documented               Filter functions with docstrings
  --undocumented             Filter functions without docstrings
  --public                   Filter for symbols without a _ prefix
  --private                  Filter for symbols with a _ prefix
  --dunder                   Filter for symbols matching __*__
  --typed                    Filter functions with type annotations
  --untyped                  Filter functions without type annotations
  --partially-typed          Filter functions with partial type annotations
  --fully-typed              Filter functions with full type annotations
  --no-init                  Filter to exclude any __init__ methods
  --check                    Exit with non-zero code if any matches found
  --replace                  Replace matching symbol with text from stdin
  --rexec TEXT               Replace with the result of piping to this tool
  --csv                      Output as CSV
  --tsv                      Output as TSV
  --json                     Output as JSON
  --nl                       Output as newline-delimited JSON
  --id-prefix TEXT           Prefix to use for symbol IDs
  --help                     Show this message and exit.

开发

要为此工具做出贡献,首先检出代码。然后创建一个新的虚拟环境

cd symbex
python -m venv venv
source venv/bin/activate

现在安装依赖项和测试依赖项

pip install -e '.[test]'

要运行测试

pytest

只需

您还可以安装just并使用它来运行测试和linters,例如

just

或列出命令

just -l
Available recipes:
    black         # Apply Black
    cog           # Rebuild docs with cog
    default       # Run tests and linters
    lint          # Run linters
    test *options # Run pytest with supplied options

项目详情


下载文件

下载适合您平台的文件。如果您不确定要选择哪个,请了解更多关于安装包的信息。

源分布

symbex-1.4.tar.gz (30.8 kB 查看散列)

上传时间

构建分布

symbex-1.4-py3-none-any.whl (20.7 kB 查看散列)

上传时间 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面