Python带数据目录的包:如何实现干净卸载?
问题根源
pip卸载时仅会删除安装过程中记录在包dist-info目录下RECORD文件里的文件,你动态生成的数据文件不在该记录中,因此会被判定为"手动添加"而保留。
解决方案
方案1:动态更新RECORD文件(让pip识别数据文件为包的一部分)
在生成数据文件后,手动将文件条目追加到RECORD中,让pip认为这些文件属于包的一部分,卸载时自动删除。
示例实现代码:
import os import hashlib from importlib.metadata import distribution def add_files_to_record(): # 获取包的分发信息 dist = distribution("my_package") dist_root = dist.locate_file("") record_path = os.path.join(dist_root, f"{dist.metadata['Name']}-{dist.version}.dist-info", "RECORD") data_dir = os.path.join(os.path.dirname(__file__), "data") if not os.path.exists(data_dir): return # 遍历数据目录并写入RECORD with open(record_path, "a", encoding="utf-8") as record_file: for root, _, files in os.walk(data_dir): for file in files: file_abspath = os.path.join(root, file) file_relpath = os.path.relpath(file_abspath, dist_root) # 计算文件哈希和大小 with open(file_abspath, "rb") as f: hash_str = hashlib.sha256(f.read()).hexdigest() file_size = os.path.getsize(file_abspath) # 写入RECORD格式条目 record_file.write(f"{file_relpath},sha256={hash_str},{file_size}\n")
在数据文件生成完成后调用该函数即可。注意:包更新时RECORD会被覆盖,需重新执行添加逻辑。
方案2:自定义卸载清理脚本(扩展setuptools命令)
通过setuptools自定义卸载命令,在原生卸载逻辑执行完成后自动清理数据目录。
- 创建包内清理模块
my_package/uninstall_cleanup.py:
from setuptools.command.uninstall import uninstall as BaseUninstall import os import shutil class CustomUninstall(BaseUninstall): def run(self): # 先执行原生卸载流程 super().run() # 清理数据目录 pkg_dir = os.path.dirname(os.path.abspath(__file__)) data_dir = os.path.join(pkg_dir, "data") if os.path.exists(data_dir): shutil.rmtree(data_dir)
- 在
pyproject.toml中配置自定义命令:
[tool.setuptools] cmdclass = { uninstall = "my_package.uninstall_cleanup.CustomUninstall" }
注意:部分pip版本可能优先使用自身卸载逻辑,需测试兼容性。
方案3:将数据文件存储到用户目录(推荐最佳实践)
避免修改包目录,将数据文件存到系统默认的用户数据目录,同时提供清理命令让用户手动删除,更符合Python包设计规范。
- 使用
appdirs库获取用户数据目录(需将appdirs添加到包依赖):
import appdirs import os data_dir = appdirs.user_data_dir("my_package") os.makedirs(data_dir, exist_ok=True) # 生成数据文件到该目录
- 在
pyproject.toml中添加清理命令:
[project.scripts] my-package-cleanup = "my_package.cleanup:main"
- 创建清理模块
my_package/cleanup.py:
import appdirs import shutil import os def main(): data_dir = appdirs.user_data_dir("my_package") if os.path.exists(data_dir): shutil.rmtree(data_dir) print("数据文件已清理") else: print("无数据文件需要清理")
用户卸载包后,可运行my-package-cleanup命令删除数据文件。
关于pyproject.toml的直接支持
目前pyproject.toml本身没有原生配置卸载自动清理的字段,上述方案1、2需结合代码与pyproject.toml配置实现,方案3是更推荐的规范做法。
内容的提问来源于stack exchange,提问作者Trantidon
相关产品推荐
相关产品推荐

