轻松导入所有第三方软件包和脚本作为通用软件包?

时间:2013-10-10 09:08:17

标签: python python-3.x import

我想在我的程序中添加一个external包,其中应包含它使用的所有配方和第三方包。我不想强迫任何人(包括我自己)安装这些软件包,更不用说版本不兼容性了。我只是 想把它们放到自己的子文件夹中并使用它们。他们, 当然,来自各种渠道。

文件夹结构应如下所示:

| main.py
|---[external]
    |---[networkx]
    |   | ...
    |---[xlrd]
    |   | ...
    | __init__.py
    | recipe1.py
    | recipe2.py

我想在我的程序中通过以下方式获取包装和食谱:

import external
import external.xlrd
from external import networkx as nx
import external.recipe1
from external import recipe2 as magic
from external import *

但是,任何包都可能包含绝对导入,导致ImportError假设external为空__init__.py

>>> import external.networkx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".\external\networkx\__init__.py", line 46, in <module>
    from networkx import release
ImportError: No module named 'networkx'

有没有一种简单的方法来制作这样的外部包装?

1 个答案:

答案 0 :(得分:0)

我做了一个这样做的功能。您需要做的就是将此行放在外部文件夹的__init__.py

__all__ = import_all(__path__)

这个函数通常可以用来导入所有子模块,即使它们是嵌套的,只需将它放到所有相关的__init__.py中。

如果您对问题有更清晰的解决方案,请与我们分享!我不接受我自己的答案。

from os import listdir
from os.path import abspath, basename, exists, isdir, join, \
    relpath, sep, splitext
from sys import path

def import_all(path__here):
    """Imports all subpackages and submodules, excluding .py
files starting with an underscore. The directories have to
have an __init__.py to get imported.

Add this line to the __init__.py:
    __all__ = import_all(__path__)"""
    result, packagepath = [], relpath(path__here[0])
    for e in listdir(packagepath):
        mod_path = join(packagepath, e)
        mod_name = splitext(basename(e))[0]
        file_to_import = (e.endswith(".py")
            and not mod_name.startswith("_"))
        dir_to_import = (isdir(mod_path)
            and exists(join(mod_path, "__init__.py")))
        if not file_to_import and not dir_to_import:
            continue
        im_str = ".".join(mod_path.split(sep)[:-1] + [mod_name])
        try:
            __import__(im_str)
        except ImportError as err:
            # In case of a subpackage countains absolute imports
            # assuming it is in the root, we put it into the
            # system path and try again.
            if abspath(packagepath) not in path:
                path.insert(0, abspath(packagepath))
                __import__(im_str)
            else:
                raise err from None
        result.append(mod_name)
    return result