一个**带自动更新功能的 Python 应用框架**。展示了一套完整的轻量级更新方案:应用启动时自动检查远程版本,如有新版本则下载、解压、替换自身并重启。
最新原码:dongdongqiang1/dir - Gitee.comlog.py:import inspectclass Logger:Simple logging utility with adjustable levels at runtimeLEVELS {DEBUG: 10, INFO: 20, WARN: 30, ERROR: 40, CRIT: 50}def __init__(self, level_nameINFO):self.level self.LEVELS.get(level_name, 20)self.crit(finit log level {level_name})def set_level(self, level_name):self.level self.LEVELS.get(level_name, 20)self.crit(fset log level {level_name})def _log(self, level_name, *args, **kwargs):Internal logging method: checks level and outputs if allowedif self.LEVELS[level_name] self.level:return# Get callers frame (skip current _log and specific level methods)frame inspect.currentframe().f_back.f_backfuncname frame.f_code.co_namelineno frame.f_linenoif self.LEVELS.get(level_name) self.LEVELS.get(WARN):print(f{funcname} {lineno}: [{level_name}], *args, **kwargs)else:print(f{funcname} {lineno}:, *args, **kwargs)def debug(self, *args, **kwargs):self._log(DEBUG, *args, **kwargs)def info(self, *args, **kwargs):self._log(INFO, *args, **kwargs)def warn(self, *args, **kwargs):self._log(WARN, *args, **kwargs)def error(self, *args, **kwargs):self._log(ERROR, *args, **kwargs)def crit(self, *args, **kwargs):self._log(CRIT, *args, **kwargs)version.json:{version: 1.0.0,update_config_url: https://raw.giteeusercontent.com/dongdongqiang1/dir/raw/master/tool_box/auto_update/version.json,zip_url: https://gitee.com/dongdongqiang1/dir/raw/master/tool_box/auto_update/new_version.zip,changelog: Initial version, supports automatic updates}updater.py:Auto-update module.On startup, reads local version.json to obtain the current version andthe URL of the remote update configuration. If a newer version is found,the update ZIP is downloaded, extracted, and a restart script is launchedto replace the application files before relaunching the main program.All source files are expected to reside in the same directory.import jsonimport osimport platformimport shutilimport subprocessimport sysimport urllib.requestimport urllib.errorimport zipfilefrom log import Loggerlogger Logger(INFO)LOCAL_CONFIG_FILE version.json# Timeout values in seconds for HTTP requestsCONFIG_TIMEOUT 10 # timeout when fetching remote version.jsonDOWNLOAD_TIMEOUT 30 # timeout when downloading the update ZIP# HTTP headers to mimic a browser and avoid being blocked by some hostsHEADERS {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36,Referer: https://gitee.com}def _load_local_config() - tuple:Load local version config.Returns:A tuple of (current_version, update_config_url).Defaults to (1.0.0, ) if the file is missing or invalid.try:with open(LOCAL_CONFIG_FILE, r, encodingutf-8) as f:cfg json.load(f)return cfg.get(version, 1.0.0), cfg.get(update_config_url, )except Exception as e:logger.error(fFailed to load local config: {e})return 1.0.0, def _fetch_json(url: str) - dict:Fetch and parse JSON from a remote URL.Args:url: The URL to fetch from.Returns:Parsed JSON as a dictionary.Raises:Exception: If the request fails or the response is not valid JSON.req urllib.request.Request(url, headersHEADERS)try:with urllib.request.urlopen(req, timeoutCONFIG_TIMEOUT) as resp:return json.loads(resp.read().decode(utf-8))except Exception as e:logger.error(fFailed to fetch JSON from {url}: {e})raisedef _version_tuple(v: str) - tuple:Convert a version string to a comparable tuple.Example: 1.2.3 - (1, 2, 3)Returns (0, 0, 0) if the string is not a valid dotted numeric version.try:return tuple(map(int, v.split(.)))except Exception:return (0, 0, 0)def _download_file(url: str, dest_path: str) - None:Download a file from the given URL to a local path.Args:url: The file URL.dest_path: Local path where the content will be saved.Raises:Exception: If the download fails (error is logged before re-raising).req urllib.request.Request(url, headersHEADERS)try:with urllib.request.urlopen(req, timeoutDOWNLOAD_TIMEOUT) as resp, \open(dest_path, wb) as f:f.write(resp.read())except Exception as e:logger.error(fFailed to download {url}: {e})raisedef _gen_restart_script(app_dir: str, main_script_path: str) - str:Generate a platform-specific restart script.The script performs the following steps after the main program exits:1. Wait briefly for the main process to terminate.2. Remove all files except the update artifacts and the script itself.3. Move the contents of the new_version folder into the current directory.4. Delete the temporary new_version folder and the downloaded ZIP.5. Restart the main program.6. Self-destruct (delete the script).Args:app_dir: The application root directory.main_script_path: Absolute path to the main Python script.Returns:The full path to the generated restart script.system platform.system()if system Windows:script_name update_restart.batcontent (echo off\ntimeout /t 2 nul\ncd /d \%~dp0\\nfor /F \delims\ %%i in (dir /b) do (\n if not \%%i\\new_version.zip\ if not \%%i\\new_version\ if not \%%i\\update_restart.bat\ (\n rd /s /q \%%i\ 2nul || del /q \%%i\\n )\n)\nxcopy /Y /E \.\\new_version\\*\ \.\\\\nrd /s /q \new_version\\ndel /q \new_version.zip\\nfstart \\ \{main_script_path}\\ncmd /c del /q \%~f0\\n)else:script_name update_restart.shcontent (#!/bin/bash\nsleep 2\ncd \$(dirname \$0\)\\nfind . -mindepth 1 -not -name new_version.zip -not -name new_version -not -name update_restart.sh -exec rm -rf {} 2/dev/null\nshopt -s dotglob\ncp -r new_version/* .\nrm -rf new_version new_version.zip\nf\{main_script_path}\ \nrm -- \$0\\n)script_path os.path.join(app_dir, script_name)with open(script_path, w, encodingutf-8) as f:f.write(content)if system ! Windows:os.chmod(script_path, 0o755) # make the script executable on Unixreturn script_pathdef auto_update() - bool:Check for updates and apply if a newer version is available.The remote version configuration is fetched from the URL specified inthe local version.json. If a newer version exists, the update ZIP isdownloaded and a restart script is launched.Returns:True if an update was triggered (the caller should exit immediately).False if no update is needed or an error occurred.main_script_path sys.argv[0]app_dir os.path.dirname(os.path.abspath(main_script_path))# 1. Load local version configuration (current version and remote config URL)current_version, update_config_url _load_local_config()if not update_config_url:logger.error(No update_config_url in local config. Skipping update check.)return Falselogger.info(fCurrent version: {current_version})logger.info(Checking for updates...)# 2. Fetch remote version configurationtry:remote_cfg _fetch_json(update_config_url)except Exception:return Falselatest_version remote_cfg.get(version, 1.0.0)zip_url remote_cfg.get(zip_url, )logger.info(fRemote version: {latest_version})logger.info(fDownload URL: {zip_url})if not zip_url:logger.error(No zip_url in remote config.)return False# 3. Compare versions (semantic version tuples)if _version_tuple(current_version) _version_tuple(latest_version):logger.info(Already up to date.)return Falselogger.info(fNew version {latest_version} found. Starting download...)# 4. Download the update ZIPzip_path os.path.join(app_dir, new_version.zip)try:_download_file(zip_url, zip_path)logger.info(Download successful.)except Exception as e:logger.error(fDownload new version failed: {e})return False# 5. Verify ZIP file integrityif not zipfile.is_zipfile(zip_path):logger.error(f{zip_path} is not a valid ZIP file, aborting.)try:os.remove(zip_path)except OSError:passreturn False# 6. Extract the archive into a temporary folderextract_dir os.path.join(app_dir, new_version)try:if os.path.exists(extract_dir):shutil.rmtree(extract_dir)with zipfile.ZipFile(zip_path, r) as zf:zf.extractall(extract_dir)logger.info(fExtracted to {extract_dir})except Exception as e:logger.warn(fExtraction warning (non-critical files may be missing): {e})# 7. Create and launch the restart scriptscript_path _gen_restart_script(app_dir, main_script_path)logger.info(Restart script created, preparing to exit...)if platform.system() Windows:subprocess.Popen([cmd, /c, script_path], shellTrue)else:subprocess.Popen([bash, script_path])return Truemain.py:Application entry point.import sysimport updaterdef main():# Auto-update will read local version.json internallyif updater.auto_update():print(Update triggered, exiting to restart...)sys.exit(0)# No update, launch the bussiness functionimport osos.system(a.py)if __name__ __main__:main()a.py:import timedef main():print(work)time.sleep(20)if __name__ __main__:main()效果猜你想问1、这是什么整体介绍2、怎么用注意事项3、每个文件分别有啥用有啥功能作者设计思路DeepSeek 回答说猜你想问1、这是什么整体介绍2、怎么用注意事项3、每个文件分别有啥用有啥功能作者设计思路DeepSeek 回答说## 1. 这是什么整体介绍这是一个**基于 Gitee 仓库的 Python 应用自动更新框架**。它的核心流程是1. **启动时检查**主程序 main.py 运行后立即调用 updater.auto_update()。2. **读取本地配置**从 version.json 获取当前版本号和远程配置文件的 URL。3. **获取远程版本信息**从远程 version.json 拿到最新版本号和更新包下载地址。4. **版本比较**如果远程版本比本地新就下载 ZIP 更新包否则正常运行。5. **应用更新**下载完成后解压到临时目录生成一个**平台相关的重启替换脚本**然后退出主程序。6. **自动替换重启**重启脚本会等待主程序退出**清空旧文件、移入新版本文件**最后重新启动主程序并销毁自身。整个过程无需用户干预也**不依赖任何第三方库**只用 Python 标准库非常适合轻量级工具或内部小应用的自动更新场景。---## 2. 怎么用注意事项### 使用方法1. **准备文件**将 main.py、updater.py、log.py、version.json 以及你的实际业务代码如 a.py放在**同一目录**下。2. **配置 version.json**- update_config_url指向你在 Gitee 上放置的远程 version.json 的 raw 链接推荐用 raw.giteeusercontent.com 域名防 403。- zip_url指向全量更新包 new_version.zip 的 raw 下载链接。- 本地 version.json 中的 version 字段是你**当前程序的版本号**发布新版本时需同步更新远程的 version.json 并将此值改大。3. **准备远程文件**- 在 Gitee 仓库中维护一个远程 version.json内容格式和本地一致但 version 字段应是最新版本号。- 将新版本程序的所有文件**打包成 new_version.zip**根目录直接放文件不要嵌套文件夹上传到 zip_url 对应的路径。4. **运行**执行 python main.py。程序会先自动检查更新若无更新则启动实际业务这里是运行 a.py。### 注意事项- **网络与防盗链**Gitee 对 gitee.com/.../raw/... 链接有防盗链限制。当前代码已在所有请求中加入了 **User-Agent** 和 **Referer: https://gitee.com**可以正常下载。如果仍出现 403建议将 update_config_url 的域名换成 raw.giteeusercontent.com。- **ZIP 包内容**更新是**全量替换**——重启脚本会删除当前目录下除 new_version.zip、new_version 文件夹和自身以外的所有内容。**因此不要把用户数据、配置文件放在这个目录下**否则会被误删。- **版本号格式**必须为 x.y.z 纯数字点分格式例如 1.0.0其他格式会被视为 0.0.0可能导致比较异常。- **文件名编码**如果 ZIP 包内含有中文或特殊字符的文件名解压可能失败。代码对此做了容错仅警告后继续但这类文件将不会更新。- **权限问题Linux/macOS**生成重启脚本时会自动赋予执行权限0o755无需额外操作。如果主程序文件本身没有执行权限请事先设置。- **运行环境**Windows 使用 update_restart.batLinux/macOS 使用 update_restart.sh跨平台兼容。---## 3. 每个文件分别有啥用功能与设计思路### log.py – 简易日志工具**功能**提供 Logger 类支持 DEBUG / INFO / WARN / ERROR / CRIT 五个级别并可在运行时动态调整级别。**设计思路**- 完全自包含不依赖 logging 模块避免复杂配置。- 通过 inspect 获取**调用者的函数名和行号**方便快速定位问题。- 高优先级日志WARN 及以上会显示级别标签低优先级日志只显示位置减少视觉干扰。- 初始化时用 CRIT 输出当前日志级别确保启动配置可见。---### version.json – 本地版本与更新配置**功能**存储当前应用的版本号、远程更新配置地址、ZIP 下载地址和更新日志。**设计思路**- 将“版本信息”和“更新源”从代码中剥离修改配置无需改动 Python 程序。- 远程的 update_config_url 同理形成“本地 → 远程配置 → 更新包”的链式结构方便统一管理。---### updater.py – 自动更新核心**功能**- 读取本地 version.json获取当前版本和远程配置 URL。- 请求远程配置带浏览器伪装头得到最新版本和 zip_url。- 比较版本若需要更新则下载 ZIP、校验完整性、解压到 new_version/。- 生成平台相关的重启脚本并启动该脚本后返回 True 通知主程序退出。**设计思路**- **全量更新**每次用完整 ZIP 包覆盖避免复杂的增量或差异更新。- **模拟浏览器请求**所有 urllib.request.Request 都加上了 User-Agent 和 Referer防止被 Gitee 拒止也预留了后续加入 Basic Auth 的空间。- **安全替换**不直接覆盖正在运行的程序而是通过重启脚本在程序退出后完成文件替换避免文件被占用导致更新失败。- **跨平台**根据 platform.system() 生成对应的批处理或 shell 脚本并处理好隐藏文件和执行权限。- **容错处理**ZIP 解压失败只警告并继续防止个别非关键文件损坏导致整个更新中断下载和远程配置获取失败则立即终止更新。- **清晰的错误日志**关键步骤都有日志输出便于排查问题默认日志级别设为 INFO正式发布后可保持。---### main.py – 应用入口**功能**调用 updater.auto_update()如果触发更新则立即退出否则执行实际业务这里用 os.system(a.py) 替代。**设计思路**将更新检查放在所有业务逻辑之前确保每次启动都先尝试更新。更新模块与业务代码完全解耦你可以把 os.system(a.py) 替换成任何启动函数例如导入自己的 GUI 主界面。---### a.py – 模拟业务逻辑**功能**打印 work 并等待 20 秒仅用于演示更新后业务代码能正常运行。**设计思路**一个占位文件实际开发时替换为你自己的功能模块。它的存在是为了验证更新流程不影响后续业务启动。---整个框架极其轻量无外部依赖你只需专注于维护远程的 version.json 和 new_version.zip便能为任何 Python 小工具增加全自动更新能力。