簡體   English   中英

如何從`src/`目錄下的python包訪問項目根目錄中的文本文件

[英]How to access text file in project root from python package under `src/` directory

我希望我的包的版本號位於一個地方,需要它的所有內容都可以引用它。

我在這個 Python 指南中找到了一些關於Single Sourcing the Package Version 的建議,並決定嘗試 #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 內部。 以下是在<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

更多我的配置文件:

清單.in :

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',
)

我發現這個問題任何 python 函數來獲取“data_files”根目錄? 這讓我認為pkg_resources庫是我問題的答案,但我一直無法弄清楚如何在我的情況下使用它。

我一直遇到麻煩,因為我發現的大多數示例都直接在項目根目錄中包含 python 包,而不是在src/目錄中隔離。 由於以下建議,我正在使用src/目錄:

我發現並嘗試稍微扭曲的其他旋鈕是package_datainclude_package_data和用於setup() data_files kwargs。 不知道他們有多大關系。 似乎用這些聲明的事物與清單中聲明的​​事物之間存在一些相互作用,但我不確定細節。

在 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

我的項目/版本

1.4.2

清單文件

include myproj/VERSION

設置文件

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 中讀取版本,然后將其包含在函數中:

設置文件

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

在完整的示例中,我選擇將所有內容都保留在 setup.py 中,以便於減少一個文件,並不確定 Cfg 解決方案是否會去除 VERSION 文件中版本周圍的潛在空白。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM