在不运行Python包的情况下检查它的内容?

战争艺术

我想要一个给定aname导致a的函数,该函数NameError可以标识可以import编辑以解决该问题的Python包

该部分相当容易,而且我已经完成了,但是现在我遇到了另一个问题:我希望做到这一点而不会引起副作用。这是我现在正在使用的代码:

def necessaryImportFor(name):
    from pkgutil import walk_packages
    for package in walk_packages():
        if package[1] == name:
            return name
        try:
            if hasattr(__import__(package[1]), name):
                return package[1]
        except Exception as e:
            print("Can't check " + package[1] + " on account of a " + e.__class__.__name__ + ": " + str(e))
    print("No possible import satisfies " + name)

问题是该代码实际上__import__是每个模块的代码这意味着导入每个模块的所有副作用都会发生。测试我的代码时,我发现由导入所有模块引起的副作用包括:

  • 启动tkinter应用程序
  • 要求输入密码 getpass
  • 请求其他inputraw_input
  • 列印讯息(import this
  • 开设网站(import antigravity

一个可能的解决方案,我认为会找到路径的每一个模块(怎么?在我看来,要做到这一点的唯一方法是通过import荷兰国际集团则利用一些方法的模块inspect就可以了),然后分析它找到每一个classdef,而且=它本身不是在classor内def,但这似乎是一个巨大的PITA,而且我认为它不适用于以C / C ++而非纯Python实现的模块。

另一种可能性是启动一个子Python实例,该实例的输出重定向到该实例并在该实例中devnull执行检查,如果花费太长时间则将其杀死。那将解决前四个子弹,而第五个子弹是一种特殊情况,我可以跳过antigravity但是必须在此单个函数中启动数千个Python实例似乎有点……繁琐且效率低下。

有没有人有我没有考虑过的更好的解决方案?例如,是否有一种简单的方法可以告诉Python生成AST或其他内容而无需实际导入模块?

战争艺术

因此,我最终写了一些方法,这些方法可以列出源文件中的所有内容,而无需导入源文件。

ast模块似乎没有特别好的文档,因此这有点像PITA,试图弄清楚如何提取感兴趣的所有内容。尽管如此,经过大约6个小时的反复试验,今天我可以将其组合在一起并在计算机上的3000多个Python源文件上运行,而没有引发任何异常。

def listImportablesFromAST(ast_):
    from ast import (Assign, ClassDef, FunctionDef, Import, ImportFrom, Name,
                     For, Tuple, TryExcept, TryFinally, With)

    if isinstance(ast_, (ClassDef, FunctionDef)):
        return [ast_.name]
    elif isinstance(ast_, (Import, ImportFrom)):
        return [name.asname if name.asname else name.name for name in ast_.names]

    ret = []

    if isinstance(ast_, Assign):
        for target in ast_.targets:
            if isinstance(target, Tuple):
                ret.extend([elt.id for elt in target.elts])
            elif isinstance(target, Name):
                ret.append(target.id)
        return ret

    # These two attributes cover everything of interest from If, Module,
    # and While. They also cover parts of For, TryExcept, TryFinally, and With.
    if hasattr(ast_, 'body') and isinstance(ast_.body, list):
        for innerAST in ast_.body:
            ret.extend(listImportablesFromAST(innerAST))
    if hasattr(ast_, 'orelse'):
        for innerAST in ast_.orelse:
            ret.extend(listImportablesFromAST(innerAST))

    if isinstance(ast_, For):
        target = ast_.target
        if isinstance(target, Tuple):
            ret.extend([elt.id for elt in target.elts])
        else:
            ret.append(target.id)
    elif isinstance(ast_, TryExcept):
        for innerAST in ast_.handlers:
            ret.extend(listImportablesFromAST(innerAST))
    elif isinstance(ast_, TryFinally):
        for innerAST in ast_.finalbody:
            ret.extend(listImportablesFromAST(innerAST))
    elif isinstance(ast_, With):
        if ast_.optional_vars:
            ret.append(ast_.optional_vars.id)
    return ret

def listImportablesFromSource(source, filename = '<Unknown>'):
    from ast import parse
    return listImportablesFromAST(parse(source, filename))

def listImportablesFromSourceFile(filename):
    with open(filename) as f:
        source = f.read()
    return listImportablesFromSource(source, filename)

上面的代码涵盖了名义上的问题:如何在不运行Python程序包的情况下检查它的内容?

但这给您带来了另一个问题:我如何仅从其名称获取通往Python包的路径?

这是我为处理此问题而写的:

class PathToSourceFileException(Exception):
    pass

class PackageMissingChildException(PathToSourceFileException):
    pass

class PackageMissingInitException(PathToSourceFileException):
    pass

class NotASourceFileException(PathToSourceFileException):
    pass

def pathToSourceFile(name):
    '''
    Given a name, returns the path to the source file, if possible.
    Otherwise raises an ImportError or subclass of PathToSourceFileException.
    '''

    from os.path import dirname, isdir, isfile, join

    if '.' in name:
        parentSource = pathToSourceFile('.'.join(name.split('.')[:-1]))
        path = join(dirname(parentSource), name.split('.')[-1])
        if isdir(path):
            path = join(path, '__init__.py')
            if isfile(path):
                return path
            raise PackageMissingInitException()
        path += '.py'
        if isfile(path):
            return path
        raise PackageMissingChildException()

    from imp import find_module, PKG_DIRECTORY, PY_SOURCE

    f, path, (suffix, mode, type_) = find_module(name)
    if f:
        f.close()
    if type_ == PY_SOURCE:
        return path
    elif type_ == PKG_DIRECTORY:
        path = join(path, '__init__.py')
        if isfile(path):
            return path
        raise PackageMissingInitException()
    raise NotASourceFileException('Name ' + name + ' refers to the file at path ' + path + ' which is not that of a source file.')

一起尝试这两位代码,我有这个功能:

def listImportablesFromName(name, allowImport = False):
    try:
        return listImportablesFromSourceFile(pathToSourceFile(name))
    except PathToSourceFileException:
        if not allowImport:
            raise
        return dir(__import__(name))

最后,这是我在问题中提到的功能的实现:

def necessaryImportFor(name):
    packageNames = []

    def nameHandler(name):
        packageNames.append(name)

    from pkgutil import walk_packages
    for package in walk_packages(onerror=nameHandler):
        nameHandler(package[1])
    # Suggestion: Sort package names by count of '.', so shallower packages are searched first.
    for package in packageNames:
        # Suggestion: just skip any package that starts with 'test.'
        try:
            if name in listImportablesForName(package):
                return package
        except ImportError:
            pass
        except PathToSourceFileException:
            pass
    return None

这就是我度过星期日的方式。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在不运行Python包的情况下检查它的内容?

来自分类Dev

在不运行函数的情况下获取python函数属性

来自分类Dev

在不运行.Py的情况下导入Python模块

来自分类Dev

在不声明解释器的情况下运行python脚本

来自分类Dev

如何在内容中不包含用户名的情况下检查消息内容

来自分类Dev

在不增加大小的情况下检查地图内容

来自分类Dev

如何在不运行任何内容的情况下仅获得root许可?

来自分类Dev

在不运行函数的情况下检查Clojure前提条件?

来自分类Dev

dotnet pack 可以在不添加其他 nuget 包的内容文件的情况下创建 nuget 包吗?

来自分类Dev

我如何在加载Docker容器后不运行docker-compose up的情况下运行它?

来自分类Dev

如何在不构建或安装软件包的情况下运行R软件包测试?

来自分类Dev

是否可以在不运行整个Web服务器的情况下运行(并检查)Nginx重写规则?

来自分类Dev

在不添加PPA的情况下安装软件包

来自分类Dev

在不添加PPA的情况下安装软件包

来自分类Dev

如何在不创建函数的情况下运行plpgsql?

来自分类Dev

在不暂停UI的情况下休眠运行

来自分类Dev

如何在不终止的情况下运行bash脚本

来自分类Dev

如何在不运行的情况下构建Rust示例

来自分类Dev

在不运行eval的情况下获取可迭代的Tensor

来自分类Dev

在不运行getter的情况下访问Kotlin字段

来自分类Dev

在不运行程序的情况下获取constexpr

来自分类Dev

在不刻录到DVD的情况下运行ISO

来自分类Dev

在不继承父级环境的情况下运行命令

来自分类Dev

PHP:在不访问网页的情况下运行PHP脚本?

来自分类Dev

如何在不阻止的情况下从终端运行命令?

来自分类Dev

在不启动浏览器窗口的情况下运行

来自分类Dev

如何在不阅读〜/ .profile的情况下运行sh?

来自分类Dev

ElasticSearch Ruby在不运行ElasticSearch的情况下返回结果

来自分类Dev

在不运行构建脚本的情况下进行构建

Related 相关文章

  1. 1

    在不运行Python包的情况下检查它的内容?

  2. 2

    在不运行函数的情况下获取python函数属性

  3. 3

    在不运行.Py的情况下导入Python模块

  4. 4

    在不声明解释器的情况下运行python脚本

  5. 5

    如何在内容中不包含用户名的情况下检查消息内容

  6. 6

    在不增加大小的情况下检查地图内容

  7. 7

    如何在不运行任何内容的情况下仅获得root许可?

  8. 8

    在不运行函数的情况下检查Clojure前提条件?

  9. 9

    dotnet pack 可以在不添加其他 nuget 包的内容文件的情况下创建 nuget 包吗?

  10. 10

    我如何在加载Docker容器后不运行docker-compose up的情况下运行它?

  11. 11

    如何在不构建或安装软件包的情况下运行R软件包测试?

  12. 12

    是否可以在不运行整个Web服务器的情况下运行(并检查)Nginx重写规则?

  13. 13

    在不添加PPA的情况下安装软件包

  14. 14

    在不添加PPA的情况下安装软件包

  15. 15

    如何在不创建函数的情况下运行plpgsql?

  16. 16

    在不暂停UI的情况下休眠运行

  17. 17

    如何在不终止的情况下运行bash脚本

  18. 18

    如何在不运行的情况下构建Rust示例

  19. 19

    在不运行eval的情况下获取可迭代的Tensor

  20. 20

    在不运行getter的情况下访问Kotlin字段

  21. 21

    在不运行程序的情况下获取constexpr

  22. 22

    在不刻录到DVD的情况下运行ISO

  23. 23

    在不继承父级环境的情况下运行命令

  24. 24

    PHP:在不访问网页的情况下运行PHP脚本?

  25. 25

    如何在不阻止的情况下从终端运行命令?

  26. 26

    在不启动浏览器窗口的情况下运行

  27. 27

    如何在不阅读〜/ .profile的情况下运行sh?

  28. 28

    ElasticSearch Ruby在不运行ElasticSearch的情况下返回结果

  29. 29

    在不运行构建脚本的情况下进行构建

热门标签

归档