我正在编写一个依赖于大量大型数据文件的python包。这些文件不包含在包中。相反,用户需要已经在磁盘上拥有这些文件(使用任意路径)。让我的包知道这些文件的位置的最佳方法是什么?
我一直在阅读有关setup.py
和setup.cfg
的信息,但我仍然不确定如何做到这一点。在我看来,setup.cfg
中的用户可编辑选项将是一个不错的选择,但我不知道它是否是,是否可以完成,或者如果是这样我会怎么做......
我确实看到了这个几乎相同的问题,Python 打包:在 (pip) 安装时向用户询问变量值,它侧重于 pip 期间的用户输入(在评论中不鼓励这样做)。如果这真的是一个很好的解决方案,我也对如何做到这一点感兴趣。
在我私人开发的包中,我使用了模块常量,如
DEFAULT_PATH_FILE1 = "my/path/to/file1.csv"
DEFAULT_PATH_FILE2 = "my/path/to/file2.csv"
等,以及使用这些常量初始化的属性。这对于分发来说似乎根本不可行。
你想要的不是安装期间的一次性设置(这对于现代.whl
安装也是不可能的),而是客户端在运行时随时配置库的一种方式。如果您不提供 cli,则可以使用环境变量作为提供该选项的选项,也可以查找用户定义的配置文件。
这是一个简单的配方,使用appdirs
找出应该在哪里找到配置文件。它会在导入包时加载,并告诉客户端如果配置文件不存在有多糟糕。通常,这将是:
- 编写日志消息
- 使用默认设置
- 引发某种异常
- 以上各项的组合
from logging import getLogger
from pathlib import Path
from configparser import ConfigParser
# loads .ini format files easily, just to have an example to go with
import appdirs # needs to be pip-installed
log = getLogger(__name__)
config = ConfigParser(interpolation=None)
# load config, substitute "my_package" with the actual name of your package
config_path = Path(appdirs.user_config_dir("my_package")) / "user.ini"
try:
with open(config_path) as f:
config.read_file(f, source="user")
except FileNotFoundError:
# only do whatever makes sense
log.info(f"User config expected at '{config_path}', but not found.")
config.read_string("[pathes]nfile_foo=foonfile_bar=bar") # dubious
raise ImportError(f"Can't use this module; create a config at '{config_path}'.")
class Foo:
def __init__(self):
with open(cfg["pathes"]["file_foo"]) as f:
self.data = f.read()
这听起来像运行时配置。这不是setup.py
的事,它与安装软件包有关。
对于应用配置,通常通过命令行参数、环境变量或配置文件指定此资源位置。您通常需要在用户未指定任何配置的情况下硬编码一些合理的默认路径,或者在资源不存在/未找到的情况下引发异常。
环境变量示例:
import os
DEFAULT_PATH_FILE1 = "/default/path/to/file1.csv"
PATH_FILE1 = os.environ.get("PATH_FILE1", DEFAULT_PATH_FILE1)