如何合理存储Python CLI程序--version参数对应的版本信息?
嘿,这个需求太合理了——把版本信息从代码里抽出来交给构建流水线维护,还得防用户瞎改,我给你几个实用的方案,你按需选:
方案1:独立版本文件+包内存储
最直接的方式是把版本信息放在一个单独的内部模块里,比如_version.py,让构建流水线负责更新这个文件的内容,然后在主程序里导入使用。
步骤:
- 在你的项目包目录下创建
_version.py,内容就一行:
__version__ = "2.0.0"
- 构建流水线可以用脚本(比如sed、Python脚本)批量更新这个文件的版本号,比如CI里执行:
sed -i "s/__version__ = .*/__version__ = \"2.0.1\"/" myapp/_version.py
- 主程序里这样调用:
import argparse from myapp._version import __version__ def main(): parser = argparse.ArgumentParser(prog='myapp') # 把导入的版本号传入version参数 parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}') # 其他参数配置... args = parser.parse_args() if __name__ == '__main__': main()
防修改技巧:
把_version.py放在你的Python包内部目录(不是项目根目录),当你用setuptools打包成wheel或者用PyInstaller打包成可执行文件时,这个文件会被打包到产物里。用户拿到的是打包后的包/可执行文件,想要修改版本信息就得深入包内部或者反编译,普通用户基本做不到。
方案2:用项目配置文件存版本+读取包元数据
如果你的CLI是一个可安装的Python包,推荐把版本统一存在pyproject.toml里(现在Python项目的标准配置文件),然后从包的元数据里读取版本号,这样构建工具和流水线都能统一管理版本。
步骤:
- 在
pyproject.toml里定义版本:
[project] name = "myapp" version = "2.0.0"
- 构建流水线直接修改这个toml文件的
version字段就行,比如用Python的tomli-w库来更新,比sed更靠谱:
import tomli_w import tomli with open("pyproject.toml", "rb") as f: config = tomli.load(f) config["project"]["version"] = "2.0.1" with open("pyproject.toml", "wb") as f: tomli_w.dump(config, f)
- 主程序里读取版本:
import argparse from importlib.metadata import version, PackageNotFoundError def main(): prog_name = 'myapp' try: # 从已安装的包元数据里读版本 app_version = version(prog_name) except PackageNotFoundError: # 本地开发环境没安装包时, fallback到本地的_version.py from myapp._version import __version__ as app_version parser = argparse.ArgumentParser(prog=prog_name) parser.add_argument('--version', action='version', version=f'%(prog)s {app_version}') args = parser.parse_args() if __name__ == '__main__': main()
防修改技巧:
用户安装包后,版本信息存在Python的site-packages目录下的元数据文件里,普通用户不会去修改这些文件,而且修改后也会被下次安装覆盖,安全性很高。
方案3:打包时注入版本(适合独立可执行文件)
如果你的CLI最终要打包成无需Python环境的独立可执行文件(比如用PyInstaller),可以在构建时通过环境变量注入版本号,程序运行时读取这个变量,用户完全接触不到源码,根本没法修改。
步骤:
- 主程序里读取环境变量:
import argparse import os def main(): prog_name = 'myapp' # 从环境变量读版本,没读到就用unknown兜底 app_version = os.getenv('APP_VERSION', 'unknown') parser = argparse.ArgumentParser(prog=prog_name) parser.add_argument('--version', action='version', version=f'%(prog)s {app_version}') args = parser.parse_args() if __name__ == '__main__': main()
- 构建流水线打包时设置环境变量:
# Linux/macOS APP_VERSION=2.0.0 pyinstaller --onefile --name myapp main.py # Windows PowerShell $env:APP_VERSION="2.0.0"; pyinstaller --onefile --name myapp main.py
防修改技巧:
用户拿到的是编译后的二进制可执行文件,看不到任何源码,想要修改版本号就得反编译二进制,难度极大,完全满足你的防修改需求。
内容的提问来源于stack exchange,提问作者BeeShopRocks
相关产品推荐
相关产品推荐

