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

2024-09-30 03:24:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我对以下情况很好奇。假设我有两个名为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的内容: 在

^{pr2}$

project_alphasetup.py脚本非常简单。命名空间包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(),
)

project_bravosetup.py脚本具有相同的结构,但有一个转折:project_bravo依赖于{}生成: 在

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.versionproject_bravo/setup.py中的导入,并用一些硬编码的字符串替换{},那么构建会突然成功。。。在


编辑:我介绍了一个解决这个问题的方法。与其直接导入版本,不如使用版本模块来避免导入问题。当然,这不是一个合适的解决方案,因此不将其作为答案发布,但它仍然存在: 在

__version__ = None # if the exec fails, leave the version unset, the resulting build version will be 0.0.0
version_script_path = os.path.relpath(os.path.join(os.path.dirname(__file__), 'mymeta', 'project_alpha', 'version.py'))
with open(version_script_path) as version_script:
    exec(version_script.read())

在读取并执行版本脚本之后,版本被初始化,因此不需要从mymeta包中导入任何内容。在


Tags: inpyprojectversionlibpackagessetupline
2条回答

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

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

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

要使setuptools满意,还需要调整两个安装脚本:

^{pr2}$

现在,在生成project-bravo时将正确解析导入。

正如评论中提到的:命令

$ python setup.py sdist

for mymeta.project_bravo从私有pypi repo下载一个mymeta.project_alpha的鸡蛋。

命名空间包对于它们的导入非常敏感。

例如,我发现,当我在我的环境中定期安装ns.a和{},并在site packages目录中的.pth文件中提供ns.d的导入路径时,不管怎样,它都无法工作。但是,当我符号链接到site packeges/ns目录中的ns.d时,它将起作用。

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

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

只是当我混合概念的时候它就不起作用了。

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

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

^{pr2}$

我后悔我做命名空间包的决定。我再也不会这样做了。

相关问题 更多 >

    热门问题