如何在 Python3 中使用 pyclbr 搜索 __main__ 模块?

How to search for a __main__ module using pyclbr in Python3?

我想获取源代码目录:/tmp/rebound/rebound的模块:__main__中的所有函数和类。 当我使用 pyclbr.readmodule_ex API:

source_code_data = pyclbr.readmodule_ex(source_code_module, path=source_code_path)

我指定了模块及其路径:

DEBUG:root:Source code module: __main__, Source code path: ['/tmp/rebound/rebound/rebound']

然后我得到这个错误:

File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/importlib/util.py", line 69, in _find_spec_from_path
    raise ValueError('{}.__spec__ is None'.format(name))
ValueError: __main__.__spec__ is None

然后我尝试使用 public 不应该使用的函数:_readmodule:

source_code_data = pyclbr._readmodule(source_code_module, source_code_path, )

但是我无法决定参数的值应该是什么:inpackage

通过调试器跟踪代码时,我发现了一个错误:

def _find_spec_from_path(name, path=None):
    """Return the spec for the specified module.

    First, sys.modules is checked to see if the module was already imported. If
    so, then sys.modules[name].__spec__ is returned. If that happens to be
    set to None, then ValueError is raised. If the module is not in
    sys.modules, then sys.meta_path is searched for a suitable spec with the
    value of 'path' given to the finders. None is returned if no spec could
    be found.

    Dotted names do not have their parent packages implicitly imported. You will
    most likely need to explicitly import all parent packages in the proper
    order for a submodule to get the correct spec.

    """
    if name not in sys.modules:
        return _find_spec(name, path)
    else:
        module = sys.modules[name]
        if module is None:
            return None
        try:
            spec = module.__spec__
        except AttributeError:
            raise ValueError('{}.__spec__ is not set'.format(name)) from None
        else:
            if spec is None:
                raise ValueError('{}.__spec__ is None'.format(name))
            return spec

这是模块中的函数:python3.8/importlib/util.py,它将 __main__ 计算为内置模块,因为它属于 else 块。

如何区分要读取的目标源代码 __main__ 和内置的 __main__?换句话说,我如何阅读代码库的模块__main__:rebound?

TL:DR

尝试:

source_code_data = pyclbr.readmodule_ex("rebound.__main__", path=source_code_path)

说明

如您所知:_find_spec_from_path 将在 sys.modules 中搜索 name 并且 __main__ 总是在那里。

如果您检查 sys.modules.keys(),您会注意到它包含以点分隔的模块名称。 来自 Ipython shell 的示例:

 'IPython.display',
 'IPython.extensions',
 'IPython.extensions.storemagic',
 'IPython.lib',
 'IPython.lib.backgroundjobs',
 'IPython.lib.clipboard',
 'IPython.lib.display',
 'IPython.lib.pretty',
 'IPython.lib.security',
 'IPython.paths',

如果您意识到您正在寻找 rebound.__main__ 而不是 __main__,那么这就很明显了。为了进入 if 块,name 不能在 sys.modules 中。最后要说的是 _find_spec_from_path 没有错误。

# python3.8/importlib/util.py
def _find_spec_from_path(name, path=None):
    # ...
    if name not in sys.modules:
        return _find_spec(name, path)
    else:
    #...