首页 > 解决方案 > 使用配置文件打包 python 应用程序?

问题描述

我正在编写一个 Python CLI 应用程序并想要打包它。我需要应用程序有一个适用于整个“安装”的配置文件(即无论用户从哪里调用我的 CLI 应用程序,它都需要读取此配置文件)。

如果可以避免的话,我希望它位于包安装目录中,而不仅仅是文件系统上的某个任意位置。这样做的简单方法是什么?

标签: pythonpython-packaging

解决方案


很抱歉给出“这不是你想要做的”的答案,但我强烈建议不要将可编辑的配置文件捆绑到你的包中。原因是:

  • 任何严肃的操作系统都有明确定义的标准,用户或系统级配置应该去。将您的应用程序的配置也放在那里一点也不杂乱。
  • Python 包(读取、.wheel文件)不需要解压缩即可运行,因此任何支持 python 的操作系统都可能在安装时选择不这样做。如果要编辑其中的配置,则需要先解压缩包,这有点不方便。
  • 出于同样的原因,无法使用搜索工具找到配置。如果您的用户忘记了它的位置,那么祝他们好运。
  • 最后也是最不重要的,假设可执行文件是静态的。在编译代码的其他语言中,没有办法不编译,但对于解释性语言,我认为效仿是一种很好的风格。

但是遵循标准的最佳理由通常是您可以使用支持该标准的编写良好的工具,在这种情况下appdirs。它可以(除其他外)为您找到通用的配置目录,因此使用它就像这样简单:

from pathlib import Path
from appdirs import site_config_dir
from configparser import ConfigParser


def load_config():
    # .ini is easiest to work with, but .toml is probably better in the long run
    cfg_loc = Path(site_config_dir(appname="my_cli_app", appauthor="K4KFH")) / "config.ini"
    # that's it, that was the magic. the rest of the code here is just for illustration

    if not cfg_loc.exists():
        cfg_loc.parent.mkdir(parents=True, exist_ok=True)
        with open(config_loc) as f:
            f.write(
                "[basic]\n"
                "foo = 1\n"
            )
        print(f"Initialized new default config at {config_loc}.")

    cfg = ConfigParser()
    cfg.read(cfg_loc)
    return cfg

在 Windows 上,这将为您提供:

>>> cfg = load_config()
Initialized new default config at C:\ProgramData\K4KFH\my_cli_app\config.ini.
>>> cfg["basic"]["foo"]
1

在 debian buster 上:

>>> cfg = load_config()
Initialized new default config at /etc/xdg/my_cli_app/config.ini.
>>> cfg["basic"]["foo"]
1

推荐阅读