通过setuptools安装python模块时如何包含配置文件?

Pau*_*aul 5 python pip setuptools

我编写了一个用于机器人应用程序的模块,该模块提供对机器人特定特征的访问,以及用于使用数据的 python 和 c++ 客户端。使用 setuptools 将 python 客户端捆绑到一个模块中。

(简化的)目录结构如下所示:

<root of git repo>
??? config
?   ??? global
?   ?   ??? <files common to all robots>
?   ?   ??? ...
?   ??? robot1
?   ?   ??? camera_calibrations
?   ?   ?   ??? cam1.yml
?   ?   ?   ??? cam2.yml
?   ?   ?   ??? cam3.yml
?   ?   ??? vehicle_params.yaml
?   ??? robot2
?   ?   ??? ...
?   ??? ...
??? cpp
?   ??? <c++ client>
??? Makefile
??? python
?   ??? <namespace>
?       ??? __init__.py
?       ??? <module names>
?           ??? camera_calibrations.py
?           ??? ...
?           ??? __init__.py
??? README.md
??? requirements.txt
??? setup.py
Run Code Online (Sandbox Code Playgroud)

我的 setup.py 看起来像这样:

import os
import sys
from setuptools import setup, find_packages
from pip.req import parse_requirements
import shutil

# parse_requirements() returns generator of pip.req.InstallRequirement objects
REQUIREMENTS_FILE = os.path.join(os.path.dirname(__file__), 'requirements.txt')
dependencies = map(lambda ir: str(ir.req), parse_requirements(REQUIREMENTS_FILE, session='hack'))

CONFIG_FOLDER = os.path.join(os.path.dirname(__file__), 'config')
MODULE_DIR = os.path.join(sys.prefix, 'local', 'lib', 'python2.7', 'dist-packages', 'namespace', 'module_name')

def get_config_files():
    for root, _, files in os.walk(CONFIG_FOLDER):
        for filename in files:
            yield os.path.join(root, filename)

setup(
    name                 = "namespace.module_name",
    version              = "1.0.0",
    packages             = ['namespace.module_name'],
    package_dir          = {'': 'python'},
    #package_data         = {'': get_config_files()},
    install_requires     = dependencies,
    include_package_data = True,
    #data_files           = [(os.path.join(MODULE_DIR, 'config'), get_config_files())]
)

# Copy config files
## TODO: There's probably a better way to do this, but I've been working
## on it all morning soo....
CONFIG_DEST = os.path.join(MODULE_DIR, 'config')
if os.path.exists(CONFIG_DEST):
    shutil.rmtree(CONFIG_DEST)
shutil.copytree(CONFIG_FOLDER, CONFIG_DEST)
Run Code Online (Sandbox Code Playgroud)

我希望 python 客户端始终能够找到相对于自身的配置 (yml) 文件。因此,如果您从 repo 中的源代码运行它,它会在本地文件夹中找到副本。如果pip installed 并作为包导入,安装过程应该将配置文件与文件一起.py复制,然后加载它。

我选择的 hack 仅在用户以 root 身份安装时才有效,因此不是真正的解决方案。我还尝试了 中的package_datadata_files选项setup,但这些也没有完全奏效(您可以看到我尝试过的内容,我已将其注释掉)。

我还在 python 客户端中编写了这个实用程序函数,它显示了我的更多技巧:

def get_config_dir():
    # pylint: disable=global-statement
    global CONFIG_DIR
    if CONFIG_DIR is None:
        # HACK HACK HACK
        search = [
            os.path.join(CUR_DIR, 'config'),
            os.path.join(CUR_DIR, '..', '..', '..', 'config'),
            os.path.join('..', '..', '..', 'config'),
        ]
        for path in search:
            if os.path.exists(path):
                CONFIG_DIR = os.path.abspath(path)
                return CONFIG_DIR
        raise CouldNotFindConfigFolderException("Could not find config folder")
    return CONFIG_DIR
Run Code Online (Sandbox Code Playgroud)

如果有人能指出我如何正确实现这一目标的正确方向,我将不胜感激。

一个注意事项是配置文件与代码一起保存而不是系统上的其他地方很重要,因为配置可能会在版本控制下更改,并且更改与代码保持耦合是至关重要的。