如何从`src/`目录下的python包访问项目根目录中的文本文件

Pet*_*nry 5 python versioning setuptools pkg-resources setup.py

我希望我的包的版本号位于一个地方,需要它的所有内容都可以引用它。

我在这个 Python 指南中找到了一些关于单一采购包版本的建议,并决定尝试 #4,将它存储在我的项目根目录中的一个简单的文本文件中,名为VERSION.

这是我的项目目录树的缩短版本(您可以在 GitHub 上查看完整的项目):

.
??? MANIFEST.in
??? README.md
??? setup.py
??? VERSION
??? src/
?   ??? fluidspaces/
?       ??? __init__.py
?       ??? __main__.py
?       ??? i3_commands.py
?       ??? rofi_commands.py
?       ??? workspace.py
?       ??? workspaces.py
??? tests/
    ??? test_workspace.py
    ??? test_workspaces.py
Run Code Online (Sandbox Code Playgroud)

由于VERSIONsetup.py是兄弟姐妹,因此很容易阅读安装脚本中的版本文件并使用它做任何我想做的事情。

但是VERSIONsrc/fluidspaces/__main__.py并且不是兄弟,并且主模块不知道项目根的路径,所以我不能使用这种方法。

导游有这样的提醒:

警告:使用这种方法,您必须确保 VERSION 文件包含在您的所有源代码和二进制分发版中(例如,将 include VERSION 添加到您的 MANIFEST.in)。

这似乎是合理的 - 而不是需要项目根路径的包模块,版本文件可以在构建时复制到包中以便于访问 - 但我将该行添加到清单中,版本文件似乎仍然没有显示在任何地方构建。

为了构建,我pip install -U .从项目根目录和 virtualenv 内部运行。以下是<virtualenv>/lib/python3.6/site-packages结果创建的文件夹:

fluidspaces/
??? i3_commands.py
??? __init__.py
??? __main__.py
??? __pycache__/  # contents snipped
??? rofi_commands.py
??? workspace.py
??? workspaces.py
fluidspaces-0.1.0-py3.6.egg-info/
??? dependency_links.txt
??? entry_points.txt
??? installed-files.txt
??? PKG-INFO
??? SOURCES.txt
??? top_level.txt
Run Code Online (Sandbox Code Playgroud)

更多我的配置文件:

清单.in :

include README.md
include VERSION
graft src
prune tests
Run Code Online (Sandbox Code Playgroud)

设置.py

#!/usr/bin/env python3

from setuptools import setup, find_packages


def readme():
    '''Get long description from readme file'''
    with open('README.md') as f:
        return f.read()


def version():
    '''Get version from version file'''
    with open('VERSION') as f:
        return f.read().strip()


setup(
    name='fluidspaces',
    version=version(),
    description='Navigate i3wm named containers',
    long_description=readme(),
    author='Peter Henry',
    author_email='me@peterhenry.net',
    url='https://github.com/mosbasik/fluidspaces',
    license='MIT',
    classifiers=[
      'Development Status :: 3 - Alpha',
      'Programming Language :: Python :: 3.6',
    ],
    packages=find_packages('src'),
    include_package_data=True,
    package_dir={'': 'src'},
    package_data={'': ['VERSION']},
    setup_requires=[
        'pytest-runner',
    ],
    tests_require=[
        'pytest',
    ],
    entry_points={
        'console_scripts': [
            'fluidspaces = fluidspaces.__main__:main',
        ],
    },
    python_requires='~=3.6',
)
Run Code Online (Sandbox Code Playgroud)

我发现这个问题任何 python 函数来获取“data_files”根目录?这让我觉得pkg_resources图书馆是我问题的答案,但我一直无法弄清楚如何在我的情况下使用它。

我一直遇到麻烦,因为我发现的大多数示例都直接在项目根目录中使用 python 包,而不是在src/目录中隔离。src/由于以下建议,我正在使用目录:

我发现,并试图扭转一点点其他的旋钮是package_datainclude_package_datadata_files对kwargs setup()。不知道他们有多大关系。似乎用这些声明的事物与清单中声明的​​事物之间存在一些相互作用,但我不确定细节。

Pet*_*nry 2

在 Freenode 的 #python IRC 频道中与一些人讨论了这个问题。我学会了:

  • pkg_resources可能是我应该如何做我所要求的事情,但它需要将版本文件放在包目录中而不是项目根目录中。
  • setup.py可以从包目录中读取这样的版本文件,而无需导入包本身(出于某些原因,这是不行的),但它需要对从根到包的路径进行硬编码,这是我想避免的。

最终我决定使用该setuptools_scm包从我的 git 标签而不是从我的存储库中的文件获取版本信息(其他人正在使用他们的包这样做,并且他们的论点很有说服力)。

结果,我setup.py很容易就得到了我的版本号:

设置.py

from setuptools import setup, find_packages

def readme():
    '''Get long description from readme file'''
    with open('README.md') as f:
        return f.read()

setup(
    name='fluidspaces',
    use_scm_version=True,  # use this instead of version
    description='Navigate i3wm named containers',
    long_description=readme(),
    author='Peter Henry',
    author_email='me@peterhenry.net',
    url='https://github.com/mosbasik/fluidspaces',
    license='MIT',
    classifiers=[
      'Development Status :: 3 - Alpha',
      'Programming Language :: Python :: 3.6',
    ],
    packages=find_packages('src'),
    package_dir={'': 'src'},
    setup_requires=[
        'pytest-runner',
        'setuptools_scm',  # require package for setup
    ],
    tests_require=[
        'pytest',
    ],
    entry_points={
        'console_scripts': [
            'fluidspaces = fluidspaces.__main__:main',
        ],
    },
    python_requires='~=3.6',
)
Run Code Online (Sandbox Code Playgroud)

但我最终不得不有一个硬编码路径来指示项目根相对于包代码应该是什么,这是我之前一直在避免的。我认为setuptools_scm GitHub 存储库上的这个问题可能就是为什么这是必要的。

src/fluidspaces/__main__.py

import argparse
from setuptools_scm import get_version  # import this function

def main(args=None):
    # set up command line argument parsing
    parser = argparse.ArgumentParser()
    parser.add_argument('-V', '--version',
                        action='version',
                        version=get_version(root='../..', relative_to=__file__))  # and call it here
Run Code Online (Sandbox Code Playgroud)