v2.8.5 - fix: resolve DuplicateOptionError on config load and replace webbrowser with QDesktopServices
fix: resolve config DuplicateOptionError and replace webbrowser with QDesktopServices
- Config: Initialize ConfigParser with strict=False and normalize DEFAULT_MAPPINGS keys to lowercase to prevent DuplicateOptionError.
- Settings: Ensure package mapping keys are lowercased before persisting to config.ini.
- UI: Replace dynamic `__import__('webbrowser')` calls with `QDesktopServices.openUrl` to fix ModuleNotFoundError in standalone builds.
- Bump version to 2.8.5.
This commit is contained in:
1 parent
31cd5345ed
commit
12d7ef32d3
4 files changed
+39
-11
No files matched your search
@@ -4,6 +4,18 @@ QPyPack 项目的所有重要变更都将记录在此文件中。
|
||||
|
||||
[English Version](./CHANGELOG_EN.md) | **中文**
|
||||
|
||||
--
|
||||
|
||||
## [2.8.5] - 2026-09-10
|
||||
|
||||
### 修复
|
||||
- 修复配置文件读取时因键名大小写映射导致 `configparser.DuplicateOptionError` 崩溃的问题
|
||||
- 修复独立打包(Standalone)环境下点击关于页面链接及 Python 下载链接时抛出 `ModuleNotFoundError: No module named 'webbrowser'` 的问题
|
||||
|
||||
### 优化
|
||||
- 配置解析器开启宽松容错模式(`strict=False`),并在加载与保存时统一做小写预去重,提升配置读写健壮性
|
||||
- 移除对 Python 标准库 `webbrowser` 的隐式动态依赖,全面改用 Qt 原生 `QDesktopServices.openUrl` 打开系统默认浏览器,提升跨平台兼容性并减少打包产物体积
|
||||
|
||||
---
|
||||
|
||||
## [2.8.4] - 2026-09-08
|
||||
|
||||
@@ -6,6 +6,18 @@ All notable changes to the **QPyPack** project will be documented in this file.
|
||||
|
||||
---
|
||||
|
||||
## [2.8.5] - 2026-09-10
|
||||
|
||||
### Fixed
|
||||
- Fixed crash caused by `configparser.DuplicateOptionError` when loading configurations with case-insensitive mapping keys.
|
||||
- Fixed `ModuleNotFoundError: No module named 'webbrowser'` when clicking About links or the Python download button in standalone frozen builds.
|
||||
|
||||
### Improved
|
||||
- Enabled non-strict parsing (`strict=False`) in `configparser` and normalized mapping keys to lowercase to ensure robust configuration I/O.
|
||||
- Replaced dynamic `webbrowser` calls with native Qt `QDesktopServices.openUrl` for better cross-platform reliability and reduced binary bundle size.
|
||||
|
||||
---
|
||||
|
||||
## [2.8.4] - 2026-09-08
|
||||
|
||||
### Fixed
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "qpypack"
|
||||
version = "2.8.4"
|
||||
version = "2.8.5"
|
||||
description = "A cross-platform GUI packaging and compilation suite based on PyInstaller and Nuitka."
|
||||
readme = "README_EN.md"
|
||||
authors = [
|
||||
|
||||
+14
-10
@@ -125,7 +125,7 @@ except ImportError:
|
||||
HAS_QT_AUDIO = False
|
||||
|
||||
__app_name__ = "QPyPack"
|
||||
__version__ = "2.8.4"
|
||||
__version__ = "2.8.5"
|
||||
__author__ = "QwejayHuang"
|
||||
__company__ = "Qwesoft"
|
||||
__description__ = "Modern Cross-Platform Python Packaging GUI Powered by PyInstaller & Nuitka"
|
||||
@@ -889,7 +889,7 @@ MATERIAL_ICONS = {
|
||||
|
||||
|
||||
def load_config(retry=True):
|
||||
config = configparser.ConfigParser()
|
||||
config = configparser.ConfigParser(strict=False)
|
||||
default_mirror = "https://pypi.org/simple"
|
||||
default_backup = "https://test.pypi.org/simple"
|
||||
|
||||
@@ -897,8 +897,12 @@ def load_config(retry=True):
|
||||
default_mirror = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
default_backup = "https://mirrors.aliyun.com/pypi/simple/"
|
||||
|
||||
clean_default_mappings = {}
|
||||
for k, v in DEFAULT_MAPPINGS.items():
|
||||
clean_default_mappings[k.lower()] = v
|
||||
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
config["Mappings"] = {k.lower(): v for k, v in DEFAULT_MAPPINGS.items()}
|
||||
config["Mappings"] = clean_default_mappings
|
||||
config["Settings"] = {
|
||||
"language": "auto",
|
||||
"engine": "PyInstaller",
|
||||
@@ -948,19 +952,19 @@ def load_config(retry=True):
|
||||
return load_config(retry=False)
|
||||
else:
|
||||
if "Mappings" not in config:
|
||||
config["Mappings"] = {k.lower(): v for k, v in DEFAULT_MAPPINGS.items()}
|
||||
config["Mappings"] = clean_default_mappings
|
||||
if "Settings" not in config:
|
||||
config["Settings"] = {}
|
||||
if "BackportRules" not in config:
|
||||
config["BackportRules"] = DEFAULT_BACKPORT_RULES
|
||||
|
||||
if "Mappings" not in config:
|
||||
config["Mappings"] = {k.lower(): v for k, v in DEFAULT_MAPPINGS.items()}
|
||||
config["Mappings"] = clean_default_mappings
|
||||
else:
|
||||
updated_map = False
|
||||
for k, v in DEFAULT_MAPPINGS.items():
|
||||
for k, v in clean_default_mappings.items():
|
||||
if k not in config["Mappings"]:
|
||||
config["Mappings"][k.lower()] = v
|
||||
config["Mappings"][k] = v
|
||||
updated_map = True
|
||||
if updated_map:
|
||||
try:
|
||||
@@ -3717,7 +3721,7 @@ class SettingsPanel(QWidget):
|
||||
QPushButton:hover {{ background-color: {hover_bg}; color: {icon_color}; }}
|
||||
QPushButton:pressed {{ background-color: {pressed_bg}; }}
|
||||
""")
|
||||
btn.clicked.connect(lambda: __import__("webbrowser").open(url))
|
||||
btn.clicked.connect(lambda checked=False, target_url=url: QDesktopServices.openUrl(QUrl(target_url)))
|
||||
return btn
|
||||
|
||||
p_github = "M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.379.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.161 22 16.416 22 12c0-5.523-4.477-10-10-10z"
|
||||
@@ -4509,7 +4513,7 @@ class SettingsPanel(QWidget):
|
||||
for r in range(self.mapping_table.rowCount()):
|
||||
item_k = self.mapping_table.item(r, 0)
|
||||
item_v = self.mapping_table.item(r, 1)
|
||||
k = item_k.text().strip() if item_k else ""
|
||||
k = item_k.text().strip().lower() if item_k else ""
|
||||
v = item_v.text().strip() if item_v else ""
|
||||
if k and v:
|
||||
config["Mappings"][k] = v
|
||||
@@ -7935,7 +7939,7 @@ class MainWindow(QMainWindow):
|
||||
msg.addButton(_("Cancel"), QMessageBox.ButtonRole.RejectRole)
|
||||
msg.exec()
|
||||
if msg.clickedButton() == btn_down:
|
||||
__import__("webbrowser").open("https://www.python.org/downloads/")
|
||||
QDesktopServices.openUrl(QUrl("https://www.python.org/downloads/"))
|
||||
return
|
||||
|
||||
validation_errors = []
|
||||
|
||||
Reference in new issue
Block a user