Skip to main content

py2winapp

一键把 Python Web 应用打包成 Windows 桌面程序。 双击 exe 即用,无需安装 Python。启动有闪屏、托盘常驻、单实例保护、自动选端口、自动开浏览器、自定义图标。

它解决什么问题?

你写了个 Flask/FastAPI 应用,想发给没有 Python 环境的用户。py2winapp 把你的 Web 应用连同 Python 解释器、依赖、启动器一起打进一个 exe。用户双击后:闪屏 → 后台起 Web 服务 → 自动开浏览器 → 托盘常驻。体验和原生桌面软件一样。

安装

pip install py2winapp

工作原理

双击 exe
  → 闪屏"正在启动…"
  → 启动器选空闲端口(5050-5200)
  → 调你的 run_web(host, port) 起本地 Web 服务
  → 自动打开浏览器访问 http://127.0.0.1:<端口>
  → 托盘常驻,关浏览器不退出,点托盘"退出"才退

本质是"本地 Web 服务 + 自动打开的浏览器 + 托盘常驻的启动器",三者由 PyInstaller 打进一个 exe。py2winapp 不修改你的源码,仅通过配置注入。

快速开始(4 步出 exe)

① 写入口函数

# myapp/web.py
from flask import Flask

def run_web(host: str, port: int, **kwargs) -> None:
    app = Flask(__name__)

    @app.route("/")
    def index():
        return "<h1>你好,桌面应用!</h1>"

    app.run(host=host, port=port, debug=False, use_reloader=False)

② 初始化项目

py2winapp init MyApp --entry-module myapp.web --with-icon

生成 py2winapp.toml + app/build/ 骨架 + 默认图标。

③ 本地调试(不打包,秒起)

py2winapp run

④ 打包成 exe(需 Windows)

py2winapp build

产物在 dist/MyApp/MyApp.exe,把整个 dist/MyApp/ 文件夹发给用户。

命令一览

命令 说明 示例
init 初始化项目 py2winapp init MyApp --entry-module myapp.web --with-icon
icon 生成自定义图标 py2winapp icon --letter A --bg red --apply
run 开发调试(不打包) py2winapp run --no-splash --no-tray
build 打包成 exe py2winapp build --mode onefile
spec 仅生成 .spec(任意平台) py2winapp spec
clean 清理构建产物 py2winapp clean --what all
inspect 环境诊断 py2winapp inspect
version 打印版本 py2winapp version

图标预设色blue green red purple orange teal pink dark black white,也支持 #RRGGBB

入口函数要求

def run_web(host: str, port: int, **kwargs) -> None
  • 必须阻塞(启动 Web 服务后不 return)。
  • hostport 由启动器注入(选好的空闲端口),不要写死。
  • **kwargs 向前兼容,别和 host/port 重名。

配置

全部参数在 py2winapp.toml(也支持 pyproject.toml[tool.py2winapp])。5 大段:[app] [icon] [runtime] [build] [output]

全字段速查

段.字段 默认 说明
app.name (必填) 显示名(exe 名)
app.slug (必填) 内部标识(小写字母+数字+下划线,小写开头)
app.version 0.1.0 版本号
app.entry.module (必填) 入口模块,如 myapp.web
app.entry.function run_web 入口函数名
app.entry.extra_kwargs {} 调用入口函数时额外传的参数(别含 host/port)
app.data.user_data_dir ${APPDATA}/${app.slug} 用户数据目录(支持变量插值)
app.data.chdir_to_user_data true 启动时切到用户数据目录
app.data.include_packages [] 强制打包的包(数据文件靠这个收集)
app.data.hidden_imports [] PyInstaller hiddenimports
app.data.excludes [] 排除的包(减小体积)
icon.source app/assets/icon.ico 图标路径
icon.auto_generate_on_missing true 缺图标时自动生成
runtime.host 127.0.0.1 监听地址(0.0.0.0 允许局域网)
runtime.port_start / port_end 5050 / 5200 端口扫描区间(end 必须 > start)
runtime.port_wait_timeout 30.0 等服务就绪秒数
runtime.enable_splash true 启动闪屏
runtime.splash_title ${app.name} 闪屏标题
runtime.splash_size [320, 120] 闪屏宽高(两个正整数)
runtime.enable_tray true 托盘常驻
runtime.enable_single_instance true 单实例保护
runtime.auto_open_browser true 自动开浏览器
runtime.browser_detach true 浏览器脱离父进程
build.mode onedir onedir(快)或 onefile(单文件)
build.console false true 保留黑框(调试用)
build.venv_dir .venv-build 打包用 venv 目录
build.isolate_venv true 每次重建 venv
build.upx false UPX 压缩(需装 UPX)
build.codesign_identity None 代码签名证书
build.dependencies.extra [] 额外 pip install 的包
output.zip_artifact false 打包后自动 zip
output.zip_name ${app.slug}-${app.version}.zip zip 文件名

变量插值

配置中 ${...} 会被替换。小写点号查应用字段:${app.name} ${app.slug} ${app.version}大写查环境变量:${APPDATA}(Windows 为 %APPDATA%,非 Windows 回退 ~/.config)、${HOME}${LOCALAPPDATA}。仅 user_data_dirsplash_titlezip_name 三个字段支持插值。改配置后必须重新 build(插值在打包时完成,写进生成的 launcher.py)。

配置校验

加载时用 pydantic v2 校验,不通过则退出码 2。常见拒绝:slug 大写/含连字符、port_end ≤ port_startmodeonedir/onefilesplash_size 不是两个正整数、缺必填字段。

适配已有项目

你的项目入口可能不是 run_web(比如是 typer CLI 或 FastAPI app 对象)。不要改原代码,新建一个适配模块即可。

FastAPI 项目适配

假设你已有 myapp/web/app.py 里的 app = FastAPI(),新建 myapp/desktop.py

import uvicorn
from .web.app import app

def run_web(host: str, port: int, **kwargs) -> None:
    uvicorn.run(app, host=host, port=port, log_level="warning", access_log=False)

然后 py2winapp init MyApp --entry-module myapp.desktop

uvicorn hidden_imports(FastAPI 项目必加,否则运行时 ModuleNotFoundError):

[app.data]
hidden_imports = [
    "uvicorn.logging", "uvicorn.loops", "uvicorn.loops.auto",
    "uvicorn.protocols", "uvicorn.protocols.http", "uvicorn.protocols.http.auto",
    "uvicorn.lifespan", "uvicorn.lifespan.on",
]

数据文件(yaml/json)打包后找不到

PyInstaller 默认只打包 .py。数据文件靠 include_packages 触发 collect_data_files 自动收集:

[app.data]
include_packages = ["myapp"]   # 包内所有非 .py 文件会被收集

运行时用 sys._MEIPASS 定位资源(打包后资源解压到临时目录):

import sys
from pathlib import Path

def resource_path(relative: str) -> Path:
    """兼容开发和打包环境。relative 如 'data/registry.yaml'"""
    base = Path(sys._MEIPASS) / "myapp" if hasattr(sys, "_MEIPASS") else Path(__file__).parent
    return base / relative

依赖配置

你项目的运行时依赖要列进 build.dependencies.extra

[build.dependencies]
extra = ["fastapi>=0.100", "uvicorn>=0.23", "jinja2>=3.1", "pyyaml>=6"]

常见问题

问题 解决
Mac/Linux 上 build 报错 PyInstaller 不能跨平台。用 py2winapp spec 生成 spec,到 Windows 上 pyinstaller xxx.spec
双击 exe 闪退 py2winapp build --console 重新打包看黑框报错;或看 %APPDATA%/<slug>/launcher-error.log
exe 太大 excludes 排除 matplotlib/numpy/pandas/PyQt 等;开 upx = true;用 onefile
FastAPI 运行时报 ModuleNotFoundError uvicorn 子模块需列入 hidden_imports(见上方)
数据文件打包后找不到 sys._MEIPASS 定位资源,include_packages 要包含你的包
端口被占 port_start/port_end 到空闲区间
第二次双击 exe 没反应 enable_single_instance = true 时正常行为,会打开已有实例的浏览器

退出码

含义
0 成功
1 通用失败
2 配置错误
3 环境不满足
4 构建失败
5 产物校验失败

技术栈

CLI: typer + rich | 配置: pydantic v2 + TOML | 模板: jinja2 | 图标: Pillow | 托盘: pystray | 闪屏: tkinter | 打包: PyInstaller

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py2winapp_cli-0.1.1.tar.gz (42.9 kB view details)

Uploaded Source

File details

Details for the file py2winapp_cli-0.1.1.tar.gz.

File metadata

  • Download URL: py2winapp_cli-0.1.1.tar.gz
  • Upload date:
  • Size: 42.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for py2winapp_cli-0.1.1.tar.gz
Algorithm Hash digest
SHA256 77476a6e2342afe6fb36a78036dd84d4e8fecebaa859d5016ce62243beb87a11
MD5 62facaed20f8d37c7ff3576f4534ffe3
BLAKE2b-256 2feebf4e9d01fed2b2a6f59b1852444db125bd350958141e18146f2926f16754

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

1 file

0.1.0

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page