与 setup.py 和包共享包版本的正确方法是什么?

新手上路,请多包涵

使用 distutilssetuptools 等,包版本在 setup.py 中指定:

 # file: setup.py
...
setup(
name='foobar',
version='1.0.0',
# other attributes
)

我希望能够从包内访问相同的版本号:

 >>> import foobar
>>> foobar.__version__
'1.0.0'

我可以将 __version__ = '1.0.0' 添加到我的包的 init.py 中,但我还想在我的包中包含其他导入以创建包的简化接口:

 # file: __init__.py

from foobar import foo
from foobar.bar import Bar

__version__ = '1.0.0'

# file: setup.py

from foobar import __version__
...
setup(
name='foobar',
version=__version__,
# other attributes
)

但是,这些额外的导入可能会导致安装 foobar 如果它们导入其他尚未安装的包,则会失败。与 setup.py 和包共享包版本的正确方法是什么?

原文由 Jace Browning 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 490
2 个回答

仅在 setup.py 中设置版本,并使用 pkg_resources 读取您自己的版本,有效查询 setuptools 元数据:

文件: setup.py

 setup(
    name='foobar',
    version='1.0.0',
    # other attributes
)

文件: __init__.py

 from pkg_resources import get_distribution

__version__ = get_distribution('foobar').version

为了使它在所有情况下都能正常工作,你可以在没有安装它的情况下运行它,测试 DistributionNotFound 和分发位置:

 from pkg_resources import get_distribution, DistributionNotFound
import os.path

try:
    _dist = get_distribution('foobar')
    # Normalize case for Windows systems
    dist_loc = os.path.normcase(_dist.location)
    here = os.path.normcase(__file__)
    if not here.startswith(os.path.join(dist_loc, 'foobar')):
        # not installed, but there is another version that *is*
        raise DistributionNotFound
except DistributionNotFound:
    __version__ = 'Please install this project with setup.py'
else:
    __version__ = _dist.version

原文由 Martijn Pieters 发布,翻译遵循 CC BY-SA 3.0 许可协议

我不相信对此有一个规范的答案,但我的方法(直接复制或从我在其他不同地方看到的内容稍作调整)如下:

文件夹层次结构(仅限相关文件):

 package_root/
 |- main_package/
 |   |- __init__.py
 |   `- _version.py
 `- setup.py

main_package/_version.py :

 """Version information."""

# The following line *must* be the last in the module, exactly as formatted:
__version__ = "1.0.0"

main_package/__init__.py :

 """Something nice and descriptive."""

from main_package.some_module import some_function_or_class
# ... etc.
from main_package._version import __version__

__all__ = (
    some_function_or_class,
    # ... etc.
)

setup.py :

 from setuptools import setup

setup(
    version=open("main_package/_version.py").readlines()[-1].split()[-1].strip("\"'"),
    # ... etc.
)

……这像罪一样丑陋……但它有效,我已经在人们分发的包裹中看到它或类似的东西,如果有的话,我希望他们知道更好的方法。

原文由 Zero Piraeus 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题