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



我希望我的包的版本号位于一个地方,在那里所有需要它的东西都可以引用它。

我在这本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

由于VERSIONsetup.py是兄弟,所以读取安装脚本中的版本文件并对其执行任何操作都非常容易

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

导游有这样的提醒:

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

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

为了构建,我从项目根目录和虚拟机中运行pip install -U .。以下是在<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

我的更多配置文件:

歧管

include README.md
include VERSION
graft src
prune tests

设置.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',
)

我发现了这个SO问题。有没有python函数可以获取"data_files"根目录?这让我觉得pkg_resources库是解决我问题的答案,但我一直不知道如何在我的情况下使用它。

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

  • PyTest:良好实践:应用程序代码之外的测试
  • Ionel Cristian Mărieș-打包Python库
  • Hynek Schlawack-测试和包装

我发现并尝试过扭转的其他旋钮是setup()package_datainclude_package_datadata_files。不知道他们有多宽容。用这些声明的东西和清单中声明的东西之间似乎有一些相互作用,但我不确定细节。

在Freenode上的#python IRC频道中与一些人就这个问题进行了交谈。我学到了:

  • pkg_resources可能是我应该如何完成我的要求,但它需要将版本文件放在包目录中,而不是项目根目录中
  • setup.py中,我可以在不导入包本身的情况下从包目录中读取这样的版本文件(出于一些原因,这是否定的),但这需要对从根到包的路径进行硬编码,我希望避免这种情况

最终,我决定使用setuptools_scm包从我的git标记而不是从我的repo中的文件中获取版本信息(其他人正在使用他们的包,他们的论点令人信服)。

因此,我很容易就在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',
)

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

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

对于仍在寻找答案的人来说,下面是我对单一采购包版本指南的第4个变体的尝试。值得注意的是,当有其他更简单的解决方案时,你为什么会选择这种解决方案。正如链接所指出的,当您有外部工具(例如CI/CD工具)可能也想轻松检查版本时,这种方法非常有用。

文件树

myproj
├── MANIFEST.in
├── myproj
│   ├── VERSION
│   └── __init__.py
└── setup.py

myproj/VERSION

1.4.2

中的歧管

include myproj/VERSION

设置.py

with open('myproj/VERSION') as version_file:
version = version_file.read().strip()
setup(
...
version=version,
...
include_package_data=True,  # needed for the VERSION file
...
)

myproj/__init__.py

import pkgutil
__name__ = 'myproj'
__version__ = pkgutil.get_data(__name__, 'VERSION').decode()

值得注意的是,在setup.cfg中设置配置是一个很好的、干净的替代方案,可以将所有内容都包含在setup.py设置函数中。您可以执行以下操作,而不是读取setup.py中的版本,然后将其包含在函数中:

设置.cfg

[metadata]
name = my_package
version = attr: myproj.VERSION

在完整的示例中,我选择将所有内容都保留在setup.py中,以方便少一个文件,并且不确定cfg解决方案是否会剥离version文件中版本周围的潜在空白。

相关内容

  • 没有找到相关文章

最新更新