v2.5.5: Docs and pyproject updates
This commit is contained in:
1 parent
da77d5cd56
commit
69a8cf6588
3 files changed
+45
-42
No files matched your search
@@ -58,7 +58,7 @@ QPyPack 是一款致力于简化 Python 应用打包流程的可视化工具。
|
||||
|
||||
您可以通过以下两种方式之使用 QPyPack:
|
||||
|
||||
### 方法一:通过 pip 安装并运行(推荐开发者使用)
|
||||
### 方法一:通过 pip 安装并运行
|
||||
|
||||
在 Python >= 3.8 的环境中,执行以下命令进行安装与启动:
|
||||
|
||||
@@ -70,7 +70,7 @@ pip install qpypack
|
||||
qpypack
|
||||
```
|
||||
|
||||
### 方法二:下载免安装独立运行版(推荐普通用户使用)
|
||||
### 方法二:下载二进制文件
|
||||
|
||||
如果您不想配置本地 Python 环境,可直接在 Release 页面下载对应系统的预编译打包版本:
|
||||
👉 [下载页面](https://github.com/Qwejay/QPyPack/releases)
|
||||
@@ -79,6 +79,19 @@ qpypack
|
||||
|
||||
## 📅 更新日志 (Changelog)
|
||||
|
||||
### [2.5.5] - 2026-07-22
|
||||
|
||||
* **消除误删风险**:优化目录 `build/dist` 智能清理,保护桌面及工作区安全。
|
||||
* **全沙盒隔离编译**:引入系统级临时目录隔离输出,彻底解决跨盘符与路径割裂异常。
|
||||
* **修复路径映射与 UX**:构建 cwd 重定向至源码目录以完美解析相对路径;修正 `open_dist` 打开逻辑。
|
||||
* **修复 pipreqs 崩溃**:尝试解决依赖自动扫描过程中的编码中断问题。
|
||||
|
||||
### [2.5.4] - 2026-07-18
|
||||
|
||||
* **新增精简模式**:自动剔除 `pip`、`unittest` 等冗余库并启用 Nuitka `-OO` 优化,大幅缩减产物体积;配套深度源码静态扫描(至多检索 500 个本地依赖),保障极致精简下的运行稳定性。
|
||||
* **修复 UPX 假性报错问题**:当未勾选 UPX 时,显式向引擎传递 `--noupx` 指令,阻断 PyInstaller 静默调用系统 UPX 造成的兼容性报错与日志干扰。
|
||||
* **修复日志中文乱码问题**:对底层命令行调用 (`subprocess`) 全面强制追加 `encoding="utf-8"` 参数,彻底解决 Windows 默认编码 (GBK) 解析字节流时引发的控制台乱码。。
|
||||
|
||||
### [2.5.3] - 2026-07-17
|
||||
|
||||
* **引擎版本锁定**:支持在高级设置中自定义 Nuitka/PyInstaller/pipreqs 的版本,杜绝上游更新导致的打包失败。
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "qpypack"
|
||||
version = "2.5.4"
|
||||
version = "2.5.5"
|
||||
description = "A cross-platform GUI packaging and compilation suite for PyInstaller and Nuitka."
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
|
||||
+29
-39
@@ -36,7 +36,7 @@ from PySide6.QtGui import QFont, QDragEnterEvent, QDropEvent, QTextCursor, QIcon
|
||||
from PySide6.QtSvg import QSvgRenderer
|
||||
|
||||
__app_name__ = "QPyPack"
|
||||
__version__ = "2.5.4"
|
||||
__version__ = "2.5.5"
|
||||
__author__ = "QwejayHuang"
|
||||
__company__ = "QwejayHuang"
|
||||
__description__ = "基于 PyInstaller 与 Nuitka 的跨平台 Python 应用打包构建工具"
|
||||
@@ -1421,11 +1421,11 @@ class SettingsPanel(QWidget):
|
||||
card2, lay2 = self._create_card("编译选项")
|
||||
lay2.setSpacing(16)
|
||||
|
||||
self.concise_log_check = QCheckBox("精简日志输出 (过滤构建引擎产生的警告信息)")
|
||||
self.auto_save_log_check = QCheckBox("自动保存编译日志 (构建失败时在输出目录落盘生成日志文件)")
|
||||
self.auto_icon_check = QCheckBox("自动检索图标 (自动匹配并绑定源文件同名 ICO/SVG 图标)")
|
||||
self.clean_all_check = QCheckBox("清理构建缓存 (构建完成后自动删除临时目录与缓存文件)")
|
||||
self.sound_notify_check = QCheckBox("启用构建提示音 (构建成功或失败时播放系统音效)")
|
||||
self.concise_log_check = QCheckBox("精简日志输出")
|
||||
self.auto_save_log_check = QCheckBox("自动保存编译日志")
|
||||
self.auto_icon_check = QCheckBox("自动检索图标")
|
||||
self.clean_all_check = QCheckBox("清理构建缓存")
|
||||
self.sound_notify_check = QCheckBox("启用构建提示音")
|
||||
|
||||
for chk in (self.concise_log_check, self.auto_save_log_check, self.auto_icon_check, self.clean_all_check, self.sound_notify_check):
|
||||
lay2.addWidget(chk)
|
||||
@@ -1685,6 +1685,7 @@ class PackingThread(QThread):
|
||||
self.venv_dir = None
|
||||
self.temp_workpath = None
|
||||
self.temp_out_dir = None
|
||||
self.temp_dist_dir = None
|
||||
self.all_raw_logs = []
|
||||
|
||||
def cancel(self):
|
||||
@@ -1695,7 +1696,7 @@ class PackingThread(QThread):
|
||||
else: self.process.kill()
|
||||
except: pass
|
||||
|
||||
def run_cmd(self, cmd, cwd=None, timeout=None):
|
||||
def run_cmd(self, cmd, cwd=None, timeout=None, silent_error=False):
|
||||
if self._is_cancelled: return False
|
||||
|
||||
timer = None
|
||||
@@ -1769,7 +1770,7 @@ class PackingThread(QThread):
|
||||
|
||||
success = self.process.returncode == 0
|
||||
|
||||
if not success and self.params.get('concise_log', True) and cmd_raw_lines:
|
||||
if not success and not silent_error and self.params.get('concise_log', True) and cmd_raw_lines:
|
||||
self.progress.emit("\n" + "!"*10 + " [诊断回溯: 以下是由于该环节执行异常产生的完整原始日志] " + "!"*10)
|
||||
self.progress.emit('\n'.join(cmd_raw_lines))
|
||||
self.progress.emit("!"*60 + "\n")
|
||||
@@ -1867,9 +1868,7 @@ class PackingThread(QThread):
|
||||
ext = ".exe" if os.name == "nt" else ""
|
||||
|
||||
try:
|
||||
self.progress.emit("[INFO] 正在初始化工作空间并清除历史构建缓存...")
|
||||
robust_rmtree(Path.cwd() / "build")
|
||||
robust_rmtree(Path.cwd() / "dist")
|
||||
self.progress.emit("[INFO] 正在初始化隔离构建环境...")
|
||||
|
||||
script_path = Path(self.params['script_path']).resolve()
|
||||
script_dir = script_path.parent
|
||||
@@ -1970,15 +1969,14 @@ class PackingThread(QThread):
|
||||
self.progress.emit(f"[INFO] 依赖分析服务源地址: {pypi_server}")
|
||||
self.progress.emit("[INFO] 正在查询各依赖库的版本,请稍候...")
|
||||
|
||||
success_pipreqs = self.run_cmd(pipreqs_cmd, timeout=15)
|
||||
success_pipreqs = self.run_cmd(pipreqs_cmd, timeout=15, silent_error=True)
|
||||
|
||||
if not success_pipreqs:
|
||||
self.progress.emit("[INFO] UTF-8 扫描受阻,正在尝试利用系统本地编码重新扫描...")
|
||||
fallback_cmd = [c for c in pipreqs_cmd if c != "utf-8"]
|
||||
if "--encoding" in fallback_cmd:
|
||||
idx = fallback_cmd.index("--encoding")
|
||||
fallback_cmd.pop(idx)
|
||||
success_pipreqs = self.run_cmd(fallback_cmd, timeout=15)
|
||||
self.progress.emit("[INFO] UTF-8 扫描受阻,正在尝试利用兼容编码重新扫描...")
|
||||
fallback_cmd = ["iso-8859-1" if c == "utf-8" else c for c in pipreqs_cmd]
|
||||
success_pipreqs = self.run_cmd(fallback_cmd, timeout=15, silent_error=True)
|
||||
if not success_pipreqs:
|
||||
self.progress.emit("[WARN] pipreqs 深度扫描因编码异常中断,已跳过。将由后续 AST 扫描引擎补全依赖。")
|
||||
|
||||
if success_pipreqs and temp_pipreqs.exists():
|
||||
self.run_cmd([python_exe, "-m", "pip", "install", "-q", "-r", temp_pipreqs.as_posix()] + pip_args)
|
||||
@@ -2014,10 +2012,12 @@ class PackingThread(QThread):
|
||||
|
||||
if engine == "PyInstaller":
|
||||
self.temp_workpath = Path(tempfile.mkdtemp(prefix="qpypack_build_")).resolve()
|
||||
self.temp_dist_dir = Path(tempfile.mkdtemp(prefix="qpypack_dist_")).resolve()
|
||||
cmd = [
|
||||
python_exe, "-m", "PyInstaller",
|
||||
"--clean",
|
||||
"--noconfirm",
|
||||
f"--distpath={self.temp_dist_dir.as_posix()}",
|
||||
f"--workpath={self.temp_workpath.as_posix()}",
|
||||
f"--name={app_name}"
|
||||
]
|
||||
@@ -2160,18 +2160,17 @@ class PackingThread(QThread):
|
||||
|
||||
cmd.append(script_posix)
|
||||
|
||||
success = self.run_cmd(cmd, cwd=Path.cwd().resolve().as_posix())
|
||||
success = self.run_cmd(cmd, cwd=script_dir.as_posix())
|
||||
if self._is_cancelled: return self.finished.emit(False, "[INFO] 构建已被终止。")
|
||||
|
||||
self.progress.emit("[INFO] 编译核心完成,正在提取并归档编译产物...")
|
||||
cwd = Path.cwd().resolve()
|
||||
|
||||
src_out = None
|
||||
if engine == "PyInstaller":
|
||||
if sys.platform == "darwin" and self.params['noconsole']:
|
||||
src_out = cwd / "dist" / f"{app_name}.app"
|
||||
src_out = self.temp_dist_dir / f"{app_name}.app"
|
||||
else:
|
||||
src_out = cwd / "dist" / (f"{app_name}{ext}" if self.params['onefile'] else app_name)
|
||||
src_out = self.temp_dist_dir / (f"{app_name}{ext}" if self.params['onefile'] else app_name)
|
||||
elif engine == "Nuitka":
|
||||
if self.params['onefile']:
|
||||
if sys.platform == "darwin" and self.params['noconsole']:
|
||||
@@ -2263,27 +2262,20 @@ class PackingThread(QThread):
|
||||
except: pass
|
||||
|
||||
if self.params['clean_all']:
|
||||
self.progress.emit("[INFO] 正在释放空间,删除虚拟环境及临时编译缓存...")
|
||||
self.progress.emit("[INFO] 正在释放空间,安全清除临时构建环境...")
|
||||
|
||||
for p in [self.venv_dir, self.temp_workpath, self.temp_out_dir]:
|
||||
for p in [self.venv_dir, self.temp_workpath, self.temp_out_dir, self.temp_dist_dir]:
|
||||
if p and p.exists(): robust_rmtree(p)
|
||||
|
||||
cwd = Path.cwd().resolve()
|
||||
app_name = self.params.get('app_name', 'app')
|
||||
|
||||
robust_rmtree(cwd / "dist")
|
||||
for p in ["build", "__pycache__", f"{app_name}.build", f"{app_name}.dist", f"{app_name}.onefile-build"]:
|
||||
robust_rmtree(cwd / p)
|
||||
for p in ["__pycache__", f"{app_name}.build", f"{app_name}.dist", f"{app_name}.onefile-build"]:
|
||||
robust_rmtree(script_dir / p)
|
||||
|
||||
spec_file = cwd / f"{app_name}.spec"
|
||||
spec_file = script_dir / f"{app_name}.spec"
|
||||
if spec_file.exists():
|
||||
try: spec_file.unlink()
|
||||
except: pass
|
||||
|
||||
crash_xml = cwd / "nuitka-crash-report.xml"
|
||||
if crash_xml.exists():
|
||||
try: crash_xml.unlink()
|
||||
except: pass
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
@@ -2713,12 +2705,10 @@ class MainWindow(QMainWindow):
|
||||
self.update_ui_state("failed")
|
||||
|
||||
def open_dist(self):
|
||||
if self.settings_panel.out_mode_combo.currentIndex() == 1:
|
||||
if self.settings_panel.out_mode_combo.currentIndex() == 1 and self.settings_panel.out_dir_edit.text().strip():
|
||||
target = Path(self.settings_panel.out_dir_edit.text().strip())
|
||||
elif self.settings_panel.clean_all_check.isChecked() and self.script_path:
|
||||
target = Path(self.script_path).parent
|
||||
else:
|
||||
target = Path.cwd() / "dist"
|
||||
else:
|
||||
target = Path(self.script_path).parent if self.script_path else Path.cwd()
|
||||
|
||||
if target.exists():
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user