提问人:Exploring 提问时间:8/13/2023 最后编辑:blhsingExploring 更新时间:8/25/2023 访问量:303
如何区分标准库调用、第三方库调用和来自存储库的 API 调用?
How can you distinguish between a standard library call, a third-party library call, and an API call from the repository?
问:
我正在处理一个项目,我必须确定特定的调用或导入是否为:
- 来自我正在使用的语言的标准库 (Python)。(我已经在考虑使用它了)
sys.stdlib_module_names
- 来自第三方库,或
- 从存储库中对某些服务进行的 API 调用。
有没有一种有效的方法或工具可以帮助我快速区分这些类型的调用或导入?我主要使用 Python,但也欢迎其他语言的方法。
我正在处理一个项目,我必须收集在该存储库中进行的库调用数据集。
我正在从事一个项目,我的目标是从 Github 编译在给定存储库中进行的函数调用数据集。
所以首先,我从 Github 下载任何给定的 python 存储库。
那么我的主要目标是:
- 提取在目标存储库中进行的所有函数调用。
- 收集这些函数调用的详细信息,包括它们使用的参数。
- 为此,我使用 Python AST(抽象语法树)解析器来检测和编目函数调用及其各自的参数。
- 我的整个分析管道都基于利用 AST 模块的 Python 脚本。
- 现在,我必须确定这些函数调用中哪些源自存储库本身。
例如,如果有一个电话
file_b.py
def abc():
....
file_a.py
import numpy as np
from file_b import abc
....
def foo():
..
x = np.linspace(-math.pi, math.pi, 2000)
y = np.sin(x)
...
..
c = abc()
我只想捕获(因为它在该存储库中定义),而不是来自 numpy 模块的调用。abc
答:
您可以使用 inspect,因为该模块似乎是为您的目的而编写的。一种简单的区分方法是使用库磁盘中的位置,给定一个使用 inspect 的函数,例如:
import os
import inspect
# "standart" library
import numpy as np
# some "local" library
import cfg
# we can assign it on a variable if needed
foo=np
print(1, os.path.dirname(os.path.abspath(foo.__file__)))
foo=cfg
print(2, os.path.dirname(os.path.abspath(foo.__file__)))
print()
#we can get the module from any function
unknown_function = np.sort
the_module = inspect.getmodule(unknown_function)
print(the_module)
print(3, os.path.dirname(os.path.abspath(the_module.__file__)))
结果是:
1 /home/datalab/workspace/conda/lib/python3.8/site-packages/numpy
2 /home/datalab/workspace/utils
<module 'numpy' from '/home/datalab/workspace/conda/lib/python3.8/site-packages/numpy/__init__.py'>
3 /home/datalab/workspace/conda/lib/python3.8/site-packages/numpy
就您而言,您似乎有 3 个类别。
- 第一个应该/将源自 conda/pip 安装(您可以使用
sys.executable
) - 来自第三方库的第二个,这应该会产生一个众所周知的路径前缀
- 第三个将在项目存储库中,这可能是众所周知的,或者例如通过运行(从存储库中)。
subprocess.check_output(['git', 'rev-parse', '--show-toplevel'])
在更复杂的情况下,Inspect 可以做的不仅仅是为您提供磁盘上的位置。下面是一个示例和一些代码。在 PythonModuleOfTheWeek 中,有更多的用途,在这里你可以找到一些进一步的例子。
实用说明:导入模块意味着运行外部代码,因此请确保您信任该代码,或者使用某种沙盒环境/方式运行它。但如何做后者本身就是一个问题。
理论说明:在极端情况下,我认为这个问题是无法确定的。形式证明可能涉及使用一个停止函数和另一个非停止函数。因此,任何可以区分两者的分析都将解决图灵的停顿问题。对于我们使用 inspect 的情况,这意味着存在 导入它们的模块可能需要很长时间。实际上,这应该不是问题,因为任何合理的模块都应该能够在合理的时间内导入。
评论
https://www.pylint.org/ 的 Pylint 提供了您需要的静态分析工具以及众多编辑器和 IDE 集成。
- 它还可以基于 Astroid 进行扩展,因此如果你的代码专门破坏了底层 linter,你可以提供一个补丁。
- 您也可以为它编写自己的插件。https://pylint.readthedocs.io/en/latest/development_guide/how_tos/plugins.html
- 在首页上,它声称它可以检查导入了什么模块,因此它知道函数来自哪里。
Pylint 输出可以推送到文本文件,您可以自定义输出的格式,然后使用自定义脚本对其进行解析。所述脚本可以隔离和标记与您的 3 个类别相关的输出行,或者您希望从输出日志中调出的其他类别和细节。
配置选项包括标准检查器和扩展,您也可以编写它们,
- 你可以告诉它忽略特定的模块(--ignored-modules)
- 您可以将路径添加到源根目录 (--source-roots) 列表,用于确定位于源根目录下的模块的包命名空间
- 您可以为给定文件生成依赖关系图 (--int-import-graph)
- 您可以强制导入顺序将模块识别为第三方库 (--known-third-party) 的一部分
- 还有更多!亲眼看看吧。
如上所述,转换模块是一种 Pylint 插件,可以针对特定模块或框架库进行定制。此外,自定义检查器可以将模块分析为原始文件流、一系列标记(流)或用于模块的 AST 表示形式的 AST。详见:https://pylint.pycqa.org/en/latest/development_guide/how_tos/custom_checkers.html#write-a-checker 和 pylint 插件对特定函数使用进行警告?
请注意,在编写脚本时,您可以使用 inspect 或 dir() 函数来检查模块,以帮助确定它们的来源。请参见:https://www.javatpoint.com/list-all-functions-from-a-python-module
例如:
import module
dir(module)
艺术
from inspect import getmembers,isfunction
import stats
print(f for f in getmembers(stats) if isfunction(f1]))
您还可以使用正则表达式和字符串解析来检查 pylint 的输出日志并相应地处理它们。虽然我之前提到过这一点,但我想强调这一点。
AST - 抽象语法树 - 帮助 Python 应用程序处理 Python 抽象语法语法的树,一个 python AST 可以遍历,每个节点及其节点都可以追溯到一个源。有关从 AST 确定模块源的其他信息,请参阅以下其他答案:
您还可以在这篇中型文章中了解有关使用 AST 的更多信息:https://medium.com/@wshanshan/intro-to-python-ast-module-bbd22cd505f7
在这篇 Pybit.es 文章中:https://pybit.es/articles/ast-intro/
评论
from xxx import *