相同名称空间中的包:无法在安装脚本中导入模块

时间:2016-09-30 08:57:55

标签: python setuptools

我对以下情况感到好奇。我们假设我有两个名为project_alphaproject_bravo的项目,它们都定义了顶级命名空间包mymeta。布局:

project_alpha/
   -> mymeta/
        -> __init__.py
        -> project_alpha/
             -> __init__.py
             -> version.py
   -> setup.py

project_bravo/
   -> mymeta/
        -> __init__.py
        -> project_bravo/
             -> __init__.py
             -> version.py
   -> setup.py

两个mymeta/__init__.py只包含行__import__('pkg_resources').declare_namespace(__name__)(根据namespace section in setuptools docs)。 version.py的内容:

__version_info__ = (0, 9, 9, 'dev0')
__version__ = '.'.join((str(entry) for entry in __version_info__)) 

setup.py的{​​{1}}脚本非常简单。声明了命名空间包project_alpha,版本取自mymeta模块:

version

# project_alpha from setuptools import find_packages, setup from mymeta.project_alpha.version import __version__ setup( name='mymeta.project-alpha', version=__version__, namespace_packages=['mymeta'], packages=find_packages(), ) 的{​​{1}}脚本具有相同的结构,但有一个变化:setup.py在构建时取决于project_bravo

project_bravo

构建project_alpha时,出现以下错误:

from setuptools import find_packages, setup
from mymeta.project_bravo.version import __version__

setup(
    name='mymeta.project-bravo',
    version=__version__,
    namespace_packages=['mymeta'],
    setup_requires=['mymeta.project-alpha'],
    packages=find_packages(),
)

不幸的是,我不明白这里的错误。它与进口订单有关,对吧?如果我在project_bravo中注释掉~/project_bravo $ python setup.py sdist Traceback (most recent call last): File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 156, in save_modules yield saved File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 197, in setup_context yield File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 246, in run_setup DirectorySandbox(setup_dir).run(runner) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 276, in run return func() File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 245, in runner _execfile(setup_script, ns) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 47, in _execfile exec(code, globals, locals) File "/tmp/easy_install-ahmxos98/mymeta.project-alpha-0.9.9.dev0/setup.py", line 6, in <module> try: ImportError: No module named 'mymeta.project_alpha' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "setup.py", line 22, in <module> packages=find_packages(), File "/usr/lib64/python3.5/distutils/core.py", line 108, in setup _setup_distribution = dist = klass(attrs) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/dist.py", line 315, in __init__ self.fetch_build_eggs(attrs['setup_requires']) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/dist.py", line 361, in fetch_build_eggs replace_conflicting=True, File "/tmp/tstenv/lib/python3.5/site-packages/pkg_resources/__init__.py", line 853, in resolve dist = best[req.key] = env.best_match(req, ws, installer) File "/tmp/tstenv/lib/python3.5/site-packages/pkg_resources/__init__.py", line 1125, in best_match return self.obtain(req, installer) File "/tmp/tstenv/lib/python3.5/site-packages/pkg_resources/__init__.py", line 1137, in obtain return installer(requirement) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/dist.py", line 429, in fetch_build_egg return cmd.easy_install(req) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 665, in easy_install return self.install_item(spec, dist.location, tmpdir, deps) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 695, in install_item dists = self.install_eggs(spec, download, tmpdir) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 876, in install_eggs return self.build_and_install(setup_script, setup_base) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 1115, in build_and_install self.run_setup(setup_script, setup_base, args) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 1101, in run_setup run_setup(setup_script, args) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 249, in run_setup raise File "/usr/lib64/python3.5/contextlib.py", line 77, in __exit__ self.gen.throw(type, value, traceback) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 197, in setup_context yield File "/usr/lib64/python3.5/contextlib.py", line 77, in __exit__ self.gen.throw(type, value, traceback) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 168, in save_modules saved_exc.resume() File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 143, in resume six.reraise(type, exc, self._tb) File "/tmp/tstenv/lib/python3.5/site-packages/pkg_resources/_vendor/six.py", line 685, in reraise raise value.with_traceback(tb) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 156, in save_modules yield saved File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 197, in setup_context yield File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 246, in run_setup DirectorySandbox(setup_dir).run(runner) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 276, in run return func() File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 245, in runner _execfile(setup_script, ns) File "/tmp/tstenv/lib/python3.5/site-packages/setuptools/sandbox.py", line 47, in _execfile exec(code, globals, locals) File "/tmp/easy_install-ahmxos98/mymeta.project-alpha-0.9.9.dev0/setup.py", line 6, in <module> try: ImportError: No module named 'mymeta.project_alpha' 的导入,并用一些硬编码的字符串替换mymeta.project_bravo.version,那么构建成功了......

编辑:我介绍了此问题的解决方法。我没有尝试直接导入版本,而是project_bravo/setup.py版本模块以避免导入问题。当然,这不是一个合适的解决方案,因此不会将其作为答案发布,但仍然是:

version

在读取并执行版本脚本之后,将初始化版本,因此无需从exec包导入任何内容。

2 个答案:

答案 0 :(得分:1)

如评论中所述:命令

$ python setup.py sdist

mymeta.project_bravo从私人pypi repo下载mymeta.project_alpha的鸡蛋。

命名空间包在进口方面非常精细。

e.g。我发现当我在我的环境中定期安装ns.ans.b并在site-packages目录中的.pth文件中提供ns.d的导入路径时,它将无效,无论。但是,当我在site-packeges / ns目录中符号链接到ns.d时,它将起作用。

如果我没有安装任何组件并提供site-packages目录中.pth中的所有路径,那么一切正常。

如果我定期安装所有组件,一切正常。

就在我混合概念时,它将不起作用。

因此我怀疑这也可能是这里的问题:导入路径的不同策略。

您可能想尝试将__init__.py文件修改为:

from pkgutil import extend_path

__path__ = extend_path(__path__, __name__)
__import__('pkg_resources').declare_namespace(__name__)

我很遗憾我决定做命名空间包。我再也不会这样做了。

答案 1 :(得分:1)

差不多一年后,我再次面临这个问题,python>=3.3的解决方案是使用PEP 420中指定的隐式命名空间包。项目结构几乎没有改变,只是pkgutil样式命名空间包__init__.py的{​​{1}}都消失了:

mymeta

要使project_alpha/ -> mymeta/ -> project_alpha/ -> __init__.py -> version.py -> setup.py project_bravo/ -> mymeta/ -> project_bravo/ -> __init__.py -> version.py -> setup.py 满意,还需要调整两个设置脚本:

setuptools

现在,在构建... setup( ... packages=['mymeta.' + pkg for pkg in find_packages('mymeta')], ) 时,将正确解析导入。