From 31cd5345ed1279bc7c62d97d6c4d3890eb06cd31 Mon Sep 17 00:00:00 2001 From: QwejayHuang Date: Tue, 8 Sep 2026 21:36:32 +0800 Subject: [PATCH] v2.8.4 - fix(scanner): prevent phantom dependencies and restore on-demand folder scanning - Add EXCLUDE_DIR_NAMES and in-place directory pruning to AST dependency scanner - Restore on-demand folder scanning in PackingThread (respect use_pipreqs_dir) - Filter out invalid modules starting with '-' or '_' during AST import extraction - Prune virtual environments and vendor folders during project entry script discovery - Enforce lowercase keys when updating default package mappings in config - Bump version to 2.8.4 --- CHANGELOG.md | 14 +++++++- CHANGELOG_EN.md | 13 +++++++ pyproject.toml | 2 +- qpypack/locales/ar_SA.json | 3 +- qpypack/locales/de_DE.json | 3 +- qpypack/locales/es_ES.json | 3 +- qpypack/locales/fr_FR.json | 3 +- qpypack/locales/it_IT.json | 3 +- qpypack/locales/ja_JP.json | 5 ++- qpypack/locales/ko_KR.json | 3 +- qpypack/locales/nl_NL.json | 3 +- qpypack/locales/pl_PL.json | 3 +- qpypack/locales/pt_BR.json | 3 +- qpypack/locales/ru_RU.json | 3 +- qpypack/locales/th_TH.json | 7 ++-- qpypack/locales/tr_TR.json | 3 +- qpypack/locales/vi_VN.json | 3 +- qpypack/locales/zh_TW.json | 7 ++-- qpypack/main.py | 70 ++++++++++++++++++++++++++++++-------- tests/test_check.py | 34 ++++++++++-------- 20 files changed, 122 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a1fbe..7dd65db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,19 @@ QPyPack 项目的所有重要变更都将记录在此文件中。 [English Version](./CHANGELOG_EN.md) | **中文** -这里为你准备的 **QPyPack v2.8.1** 精简版 Release/Changelog(分为**中文版**和**英文版**,可直接复制到 GitHub Release 或发布公告中): + +--- + +## [2.8.4] - 2026-09-08 + +### 修复 +- 修复 AST 依赖扫描引擎误入虚拟环境与捕获大量幽灵依赖并引发构建卡死/反复切源的问题 +- 修复打包构建流程强制进行全目录扫描的问题,恢复遵循“扫描整个文件夹”配置(默认仅分析主入口依赖) +- 修复拖入项目文件夹时可能误将虚拟环境或依赖包内部脚本识别为候选入口的问题 + +### 优化 +- 优化 AST 依赖扫描与项目目录解析性能,引入目录树就地剪枝机制,直接跳过依赖库与构建缓存目录 +- 规范配置项增量更新逻辑,确保向映射表中同步默认项时键名统一为小写格式 --- diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index bbcbdb9..3bccc5d 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -6,6 +6,19 @@ All notable changes to the **QPyPack** project will be documented in this file. --- +## [2.8.4] - 2026-09-08 + +### Fixed +- Fixed AST dependency scanner traversing into virtual environments and `site-packages`, preventing phantom dependencies and installation hangs. +- Fixed packaging workflow to respect the "Scan Entire Folder" option (`use_pipreqs_dir`), defaulting to single-script analysis. +- Fixed project entry script detection to prevent picking internal scripts from virtual environments or vendor directories when dragging a folder. + +### Improved +- Improved AST scanning and project traversal performance via in-place directory pruning. +- Enforced lowercase keys when incrementally synchronizing default package mappings in configuration. + +--- + ## [2.8.3] - 2026-09-05 ### Fixed diff --git a/pyproject.toml b/pyproject.toml index 3b88d00..a5e8e08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qpypack" -version = "2.8.3" +version = "2.8.4" description = "A cross-platform GUI packaging and compilation suite based on PyInstaller and Nuitka." readme = "README_EN.md" authors = [ diff --git a/qpypack/locales/ar_SA.json b/qpypack/locales/ar_SA.json index 949696c..f867b41 100644 --- a/qpypack/locales/ar_SA.json +++ b/qpypack/locales/ar_SA.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] المشروع الهدف موجود في دليل مزامنة سحابية (مثل OneDrive/Dropbox). قد تؤدي المزامنة السحابية إلى قفل ملفات البناء مؤقتًا.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] انتهت مهلة الاتصال بخادم الطابع الزمني، يتم التوقيع السريع محليًا...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] تم اكتشاف استخدام '__file__'. في وضع الملف الواحد لـ PyInstaller، استخدم 'sys._MEIPASS' لتحديد موقع ملفات الموارد المضمنة بشكل موثوق!", - "\\nProgram execution completed, press Enter to exit...": "\\nاكتمل تنفيذ البرنامج، اضغط Enter للخروج...", - "Package Mapping & Remediation": "تعيين الحزم والإصلاح" + "\\nProgram execution completed, press Enter to exit...": "\\nاكتمل تنفيذ البرنامج، اضغط Enter للخروج..." } diff --git a/qpypack/locales/de_DE.json b/qpypack/locales/de_DE.json index 561c284..dcf2a28 100644 --- a/qpypack/locales/de_DE.json +++ b/qpypack/locales/de_DE.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Zielprojekt befindet sich in einem Cloud-Sync-Verzeichnis (z.B. OneDrive/Dropbox). Cloud-Sync kann Build-Dateien vorübergehend sperren.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Zeitstempel-Server-Verbindung abgelaufen, lokale schnelle Signierung wird durchgeführt...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Verwendung von '__file__' erkannt. Im PyInstaller-Einzeldateimodus verwenden Sie 'sys._MEIPASS', um gebündelte Ressourcendateien zuverlässig zu finden!", - "\\nProgram execution completed, press Enter to exit...": "\\nProgrammausführung abgeschlossen, drücken Sie die Eingabetaste zum Beenden...", - "Package Mapping & Remediation": "Paketzuordnung & Fehlerbehebung" + "\\nProgram execution completed, press Enter to exit...": "\\nProgrammausführung abgeschlossen, drücken Sie die Eingabetaste zum Beenden..." } diff --git a/qpypack/locales/es_ES.json b/qpypack/locales/es_ES.json index 909903e..f691950 100644 --- a/qpypack/locales/es_ES.json +++ b/qpypack/locales/es_ES.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] El proyecto objetivo está en un directorio de sincronización en la nube (por ejemplo, OneDrive/Dropbox). La sincronización en la nube puede bloquear temporalmente los archivos de compilación.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Tiempo de espera agotado en la conexión al servidor de marcas de tiempo, realizando firma rápida local...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Se detectó el uso de '__file__'. En el modo de un solo archivo de PyInstaller, use 'sys._MEIPASS' para localizar de manera confiable los archivos de recursos empaquetados.", - "\\nProgram execution completed, press Enter to exit...": "\\nEjecución del programa completada, presione Enter para salir...", - "Package Mapping & Remediation": "Mapeo de paquetes y corrección" + "\\nProgram execution completed, press Enter to exit...": "\\nEjecución del programa completada, presione Enter para salir..." } diff --git a/qpypack/locales/fr_FR.json b/qpypack/locales/fr_FR.json index 9f204c4..5d6873d 100644 --- a/qpypack/locales/fr_FR.json +++ b/qpypack/locales/fr_FR.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Le projet cible se trouve dans un répertoire de synchronisation cloud (par ex. OneDrive/Dropbox). La synchronisation cloud peut temporairement verrouiller les fichiers de construction.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Délai d'attente dépassé pour le serveur d'horodatage, signature rapide locale en cours...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Utilisation de '__file__' détectée. En mode fichier unique PyInstaller, utilisez 'sys._MEIPASS' pour localiser de manière fiable les fichiers de ressources inclus !", - "\\nProgram execution completed, press Enter to exit...": "\\nExécution du programme terminée, appuyez sur Entrée pour quitter...", - "Package Mapping & Remediation": "Mappage de paquets et correction" + "\\nProgram execution completed, press Enter to exit...": "\\nExécution du programme terminée, appuyez sur Entrée pour quitter..." } diff --git a/qpypack/locales/it_IT.json b/qpypack/locales/it_IT.json index 5802251..2f37eae 100644 --- a/qpypack/locales/it_IT.json +++ b/qpypack/locales/it_IT.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Il progetto di destinazione si trova in una directory di sincronizzazione cloud (es. OneDrive/Dropbox). La sincronizzazione cloud potrebbe bloccare temporaneamente i file di build.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Timeout della connessione al server timestamp, esecuzione di firma rapida locale...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Rilevato uso di '__file__'. In modalità One-File di PyInstaller, usa 'sys._MEIPASS' per individuare in modo affidabile i file di risorse inclusi!", - "\\nProgram execution completed, press Enter to exit...": "\\nEsecuzione del programma completata, premere Invio per uscire...", - "Package Mapping & Remediation": "Mappatura pacchetti e correzione" + "\\nProgram execution completed, press Enter to exit...": "\\nEsecuzione del programma completata, premere Invio per uscire..." } diff --git a/qpypack/locales/ja_JP.json b/qpypack/locales/ja_JP.json index 15fea89..c7e87cd 100644 --- a/qpypack/locales/ja_JP.json +++ b/qpypack/locales/ja_JP.json @@ -118,6 +118,7 @@ "File": "ファイル", "Folder Mode (--onedir)": "フォルダモード(--onedir)", "Full backward compatibility": "完全な後方互換性", + "Generate": "生成する", "GitHub Repository": "GitHubリポジトリ", "Global configuration has been reset.": "グローバル設定がリセットされました。", "Hidden Imports:": "隠しインポート:", @@ -408,7 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] ターゲットプロジェクトはクラウド同期ディレクトリ (例: OneDrive/Dropbox) にあります。クラウド同期によりビルドファイルが一時的にロックされる可能性があります。", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] タイムスタンプサーバーへの接続がタイムアウトしました。ローカル高速署名を実行します...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] '__file__' の使用が検出されました。PyInstallerのワンファイルモードでは、バンドルされたリソースファイルを確実に特定するために 'sys._MEIPASS' を使用してください!", - "\\nProgram execution completed, press Enter to exit...": "\\nプログラムの実行が完了しました。終了するにはEnterキーを押してください...", - "Generate": "生成", - "Package Mapping & Remediation": "パッケージマッピングと修復" + "\\nProgram execution completed, press Enter to exit...": "\\nプログラムの実行が完了しました。終了するにはEnterキーを押してください..." } diff --git a/qpypack/locales/ko_KR.json b/qpypack/locales/ko_KR.json index 206d6ff..f820ff0 100644 --- a/qpypack/locales/ko_KR.json +++ b/qpypack/locales/ko_KR.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] 대상 프로젝트가 클라우드 동기화 디렉터리(예: OneDrive/Dropbox)에 있습니다. 클라우드 동기화로 인해 빌드 파일이 일시적으로 잠길 수 있습니다.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] 타임스탬프 서버 연결 시간이 초과되어 로컬 빠른 서명을 수행합니다...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] '__file__' 사용이 감지되었습니다. PyInstaller 원파일 모드에서는 'sys._MEIPASS'를 사용하여 번들 리소스 파일을 안정적으로 찾으십시오!", - "\\nProgram execution completed, press Enter to exit...": "\\n프로그램 실행이 완료되었습니다. 종료하려면 Enter를 누르십시오...", - "Package Mapping & Remediation": "패키지 매핑 및 수정" + "\\nProgram execution completed, press Enter to exit...": "\\n프로그램 실행이 완료되었습니다. 종료하려면 Enter를 누르십시오..." } diff --git a/qpypack/locales/nl_NL.json b/qpypack/locales/nl_NL.json index 0438b2c..f794584 100644 --- a/qpypack/locales/nl_NL.json +++ b/qpypack/locales/nl_NL.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Doelproject bevindt zich in een Cloud Sync-map (bijv. OneDrive/Dropbox). Cloud sync kan buildbestanden tijdelijk vergrendelen.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Tijdstempelserververbinding is verlopen, lokale snelle ondertekening wordt uitgevoerd...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Gebruik van '__file__' gedetecteerd. In PyInstaller One-File modus, gebruik 'sys._MEIPASS' om gebundelde bronbestanden betrouwbaar te lokaliseren!", - "\\nProgram execution completed, press Enter to exit...": "\\nProgramma-uitvoering voltooid, druk op Enter om af te sluiten...", - "Package Mapping & Remediation": "Pakkettoewijzing & Herstel" + "\\nProgram execution completed, press Enter to exit...": "\\nProgramma-uitvoering voltooid, druk op Enter om af te sluiten..." } diff --git a/qpypack/locales/pl_PL.json b/qpypack/locales/pl_PL.json index 5d484be..17913d9 100644 --- a/qpypack/locales/pl_PL.json +++ b/qpypack/locales/pl_PL.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Projekt docelowy znajduje się w katalogu synchronizacji chmurowej (np. OneDrive/Dropbox). Synchronizacja chmurowa może tymczasowo blokować pliki budowania.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Przekroczono limit czasu połączenia z serwerem znaczników czasu, wykonywanie lokalnego szybkiego podpisywania...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Wykryto użycie '__file__'. W trybie jednego pliku PyInstaller, użyj 'sys._MEIPASS', aby niezawodnie zlokalizować dołączone pliki zasobów!", - "\\nProgram execution completed, press Enter to exit...": "\\nWykonywanie programu zakończone, naciśnij Enter, aby wyjść...", - "Package Mapping & Remediation": "Mapowanie pakietów i naprawa" + "\\nProgram execution completed, press Enter to exit...": "\\nWykonywanie programu zakończone, naciśnij Enter, aby wyjść..." } diff --git a/qpypack/locales/pt_BR.json b/qpypack/locales/pt_BR.json index 91b7d52..fd9082a 100644 --- a/qpypack/locales/pt_BR.json +++ b/qpypack/locales/pt_BR.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] O projeto alvo está em um diretório de sincronização em nuvem (ex.: OneDrive/Dropbox). A sincronização em nuvem pode bloquear temporariamente os arquivos de compilação.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] O servidor de carimbo de tempo expirou, realizando assinatura local rápida...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Uso de '__file__' detectado. No modo One-File do PyInstaller, use 'sys._MEIPASS' para localizar com confiabilidade os arquivos de recursos empacotados!", - "\\nProgram execution completed, press Enter to exit...": "\\nExecução do programa concluída, pressione Enter para sair...", - "Package Mapping & Remediation": "Mapeamento de pacotes e correção" + "\\nProgram execution completed, press Enter to exit...": "\\nExecução do programa concluída, pressione Enter para sair..." } diff --git a/qpypack/locales/ru_RU.json b/qpypack/locales/ru_RU.json index bae180d..257a0e0 100644 --- a/qpypack/locales/ru_RU.json +++ b/qpypack/locales/ru_RU.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Целевой проект находится в каталоге облачной синхронизации (например, OneDrive/Dropbox). Облачная синхронизация может временно блокировать файлы сборки.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Истекло время ожидания соединения с сервером меток времени, выполняется локальная быстрая подпись...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Обнаружено использование '__file__'. В однофайловом режиме PyInstaller используйте 'sys._MEIPASS' для надежного поиска встроенных файлов ресурсов!", - "\\nProgram execution completed, press Enter to exit...": "\\nВыполнение программы завершено, нажмите Enter для выхода...", - "Package Mapping & Remediation": "Сопоставление пакетов и исправление" + "\\nProgram execution completed, press Enter to exit...": "\\nВыполнение программы завершено, нажмите Enter для выхода..." } diff --git a/qpypack/locales/th_TH.json b/qpypack/locales/th_TH.json index 64467fc..5dcb7fa 100644 --- a/qpypack/locales/th_TH.json +++ b/qpypack/locales/th_TH.json @@ -378,6 +378,8 @@ "[SUCCESS] Compilation completed, output path: {path}": "[SUCCESS] การคอมไพล์เสร็จสมบูรณ์ พาธเอาต์พุต: {path}", "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] ใช้ลายเซ็นดิจิทัลสำเร็จ!", "[Syntax Error] Source code contains syntax errors, compilation aborted:\n - File: {file}\n - Type: {type}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: Please ensure the source code runs locally before packaging.": "[Syntax Error] ซอร์สโค้ดมีข้อผิดพลาดทางไวยากรณ์ การคอมไพล์ถูกยกเลิก:\n - ไฟล์: {file}\n - ประเภท: {type}\n - บรรทัด: บรรทัดที่ {line}\n - รายละเอียด: {desc}\n\nเคล็ดลับ: โปรดตรวจสอบให้แน่ใจว่าซอร์สโค้ดทำงานได้ในเครื่องก่อนแพ็กเกจ", + "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.", + "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.", "[TIP] Script imports parent module '{mod}'. If build fails, try dragging the whole project folder here.": "[TIP] สคริปต์นำเข้าโมดูลหลัก '{mod}' หากการสร้างล้มเหลว ให้ลองลากโฟลเดอร์โปรเจกต์ทั้งหมดมาที่นี่", "[WARN] 'multiprocessing' module detected. Ensure 'multiprocessing.freeze_support()' is called under 'if __name__ == \"__main__\":' to prevent infinite process loops (fork bombs).": "[WARN] ตรวจพบโมดูล 'multiprocessing' โปรดตรวจสอบให้แน่ใจว่าได้เรียก 'multiprocessing.freeze_support()' ภายใต้ 'if __name__ == \"__main__\":' เพื่อป้องกันการวนซ้ำของกระบวนการไม่รู้จบ (fork bombs)", "[WARN] AST Analysis Exception: {error}": "[WARN] ข้อยกเว้นการวิเคราะห์ AST: {error}", @@ -407,8 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] โปรเจกต์เป้าหมายอยู่ในไดเรกทอรี Cloud Sync (เช่น OneDrive/Dropbox) การซิงก์คลาวด์อาจล็อกไฟล์ build ชั่วคราว", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] การเชื่อมต่อกับเซิร์ฟเวอร์ timestamp หมดเวลา กำลังลงนามแบบเร็วในเครื่อง...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] ตรวจพบการใช้ '__file__' ในโหมด One-File ของ PyInstaller ควรใช้ 'sys._MEIPASS' เพื่อค้นหาไฟล์ทรัพยากรที่รวมอยู่ได้อย่างน่าเชื่อถือ!", - "\\nProgram execution completed, press Enter to exit...": "\\nการทำงานของโปรแกรมเสร็จสิ้น กด Enter เพื่อออก...", - "Package Mapping & Remediation": "การจับคู่แพ็กเกจและการแก้ไข", - "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.", - "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version." + "\\nProgram execution completed, press Enter to exit...": "\\nการทำงานของโปรแกรมเสร็จสิ้น กด Enter เพื่อออก..." } diff --git a/qpypack/locales/tr_TR.json b/qpypack/locales/tr_TR.json index c9d5430..e20ae6a 100644 --- a/qpypack/locales/tr_TR.json +++ b/qpypack/locales/tr_TR.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Hedef proje bir Bulut Senkronizasyon dizininde (örn. OneDrive/Dropbox). Bulut senkronizasyonu derleme dosyalarını geçici olarak kilitleyebilir.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Zaman damgası sunucusu bağlantısı zaman aşımına uğradı, yerel hızlı imzalama yapılıyor...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] '__file__' kullanımı algılandı. PyInstaller Tek Dosya modunda, paketlenmiş kaynak dosyalarını güvenilir şekilde bulmak için 'sys._MEIPASS' kullanın!", - "\\nProgram execution completed, press Enter to exit...": "\\nProgram yürütme tamamlandı, çıkmak için Enter'a basın...", - "Package Mapping & Remediation": "Paket Eşleme ve Düzeltme" + "\\nProgram execution completed, press Enter to exit...": "\\nProgram yürütme tamamlandı, çıkmak için Enter'a basın..." } diff --git a/qpypack/locales/vi_VN.json b/qpypack/locales/vi_VN.json index 5e082a2..0017241 100644 --- a/qpypack/locales/vi_VN.json +++ b/qpypack/locales/vi_VN.json @@ -409,6 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] Dự án mục tiêu nằm trong thư mục Đồng bộ đám mây (ví dụ: OneDrive/Dropbox). Đồng bộ đám mây có thể tạm thời khóa các tệp xây dựng.", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Kết nối máy chủ dấu thời gian hết thời gian chờ, thực hiện ký nhanh cục bộ...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] Phát hiện việc sử dụng '__file__'. Trong chế độ Một tệp PyInstaller, hãy sử dụng 'sys._MEIPASS' để định vị đáng tin cậy các tệp tài nguyên được đóng gói!", - "\\nProgram execution completed, press Enter to exit...": "\\nChương trình đã thực thi xong, nhấn Enter để thoát...", - "Package Mapping & Remediation": "Ánh xạ gói & Khắc phục" + "\\nProgram execution completed, press Enter to exit...": "\\nChương trình đã thực thi xong, nhấn Enter để thoát..." } diff --git a/qpypack/locales/zh_TW.json b/qpypack/locales/zh_TW.json index cbd793c..27b9def 100644 --- a/qpypack/locales/zh_TW.json +++ b/qpypack/locales/zh_TW.json @@ -46,6 +46,7 @@ "Build Successful": "建置成功", "Build engine packages ({count}): {pkgs}": "建置引擎套件({count}):{pkgs}", "CPU Cores:": "CPU 核心數::", + "Cancel": "取消", "Cancel & Return": "取消並返回", "Cert Password:": "憑證密碼::", "Certificate Subject (e.g. My Company):": "憑證主體(例如:我的公司)::", @@ -291,6 +292,7 @@ "UPX Path:": "UPX 路徑::", "USTC (China)": "中國科學技術大學(中國)", "Undo": "復原", + "Unknown": "未知", "Use Custom Commercial Cert (Optional) ": "使用自訂商業憑證(選用)", "Use Custom Commercial Cert (Optional) ▸": "使用自訂商業憑證(選用)▸", "Use Installed Version Directly": "直接使用已安裝版本", @@ -407,8 +409,5 @@ "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] 目標專案位於雲端同步目錄(例如 OneDrive/Dropbox)。雲端同步可能暫時鎖定建置檔案。", "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] 時間戳伺服器連線逾時,執行本機快速簽章...", "[WARN] Usage of '__file__' detected. In PyInstaller One-File mode, use 'sys._MEIPASS' to reliably locate bundled resource files!": "[WARN] 偵測到 '__file__' 的使用。在 PyInstaller 單一檔案模式中,請使用 'sys._MEIPASS' 以可靠地定位捆綁的資源檔案!", - "\\nProgram execution completed, press Enter to exit...": "\\n程式執行完成,按 Enter 鍵退出...", - "Cancel": "取消", - "Package Mapping & Remediation": "套件對應與修復", - "Unknown": "未知" + "\\nProgram execution completed, press Enter to exit...": "\\n程式執行完成,按 Enter 鍵退出..." } diff --git a/qpypack/main.py b/qpypack/main.py index 5045c6e..d037752 100644 --- a/qpypack/main.py +++ b/qpypack/main.py @@ -125,7 +125,7 @@ except ImportError: HAS_QT_AUDIO = False __app_name__ = "QPyPack" -__version__ = "2.8.3" +__version__ = "2.8.4" __author__ = "QwejayHuang" __company__ = "Qwesoft" __description__ = "Modern Cross-Platform Python Packaging GUI Powered by PyInstaller & Nuitka" @@ -960,7 +960,7 @@ def load_config(retry=True): updated_map = False for k, v in DEFAULT_MAPPINGS.items(): if k not in config["Mappings"]: - config["Mappings"][k] = v + config["Mappings"][k.lower()] = v updated_map = True if updated_map: try: @@ -1193,13 +1193,27 @@ def extract_project_imports_via_ast(target_path, scan_dir: bool = False) -> set: files_to_scan = [target_path] if target_path.is_file() else [] else: files_to_scan = [] - for root, _dirs, files in os.walk(target_path): - path_parts = set(Path(root).parts) - if path_parts & {"__pycache__", ".qpypack_build", ".qpypack_venv", ".venv", "venv", "build", "dist", "env", ".env", ".git"}: + EXCLUDE_DIR_NAMES = { + "__pycache__", ".git", ".hg", ".svn", "build", "dist", + ".venv", "venv", "env", ".env", ".conda", "envs", + "site-packages", "dist-info", "egg-info", "Lib", "lib", + "node_modules", ".tox", ".nox", ".pytest_cache", ".mypy_cache" + } + for root, dirs, files in os.walk(target_path): + dirs[:] = [ + d for d in dirs + if not d.startswith((".qpypack", "qpypack")) and d not in EXCLUDE_DIR_NAMES + ] + + path_obj = Path(root) + if any(p.startswith((".qpypack", "qpypack")) for p in path_obj.parts): continue + if any(part in EXCLUDE_DIR_NAMES for part in path_obj.parts): + continue + for file in files: if file.endswith((".py", ".pyw")): - files_to_scan.append(Path(root) / file) + files_to_scan.append(path_obj / file) for file_p in files_to_scan: try: @@ -1211,17 +1225,17 @@ def extract_project_imports_via_ast(target_path, scan_dir: bool = False) -> set: if isinstance(node, ast.Import): for n in node.names: top_pkg = n.name.split(".")[0].strip() - if top_pkg: + if top_pkg and not top_pkg.startswith(("-", "_")): imports.add(top_pkg) elif isinstance(node, ast.ImportFrom): if node.level == 0 and node.module: top_pkg = node.module.split(".")[0].strip() - if top_pkg: + if top_pkg and not top_pkg.startswith(("-", "_")): imports.add(top_pkg) except Exception: pass return imports - + def query_target_env_packages(python_exe: str) -> dict: if not python_exe or not os.path.exists(python_exe): return {} @@ -5814,8 +5828,13 @@ class PackingThread(QThread): self.progress.emit(_("[INFO] Scanning project source code via AST engine...")) - scan_target = project_root if (project_root and project_root.exists()) else script_dir - ast_discovered_imports = extract_project_imports_via_ast(scan_target, scan_dir=True) + should_scan_dir = self.params.get("use_pipreqs_dir", False) + if should_scan_dir and project_root and project_root.exists(): + scan_target = project_root + else: + scan_target = build_script_path + + ast_discovered_imports = extract_project_imports_via_ast(scan_target, scan_dir=should_scan_dir) env_pkg_map = query_target_env_packages(system_python_exe) @@ -7635,13 +7654,26 @@ class MainWindow(QMainWindow): def on_project_folder_selected(self, folder_path: Path): folder_path = folder_path.resolve() candidates = [] - for root, _dirs, files in os.walk(folder_path): - parts = set(Path(root).parts) - if parts & {"__pycache__", ".git", ".venv", "venv", "build", "dist", ".qpypack_build", ".qpypack_venv"}: + EXCLUDE_DIR_NAMES = { + "__pycache__", ".git", ".hg", ".svn", "build", "dist", + ".venv", "venv", "env", ".env", ".conda", "envs", + "site-packages", "dist-info", "egg-info", "Lib", "lib", + "node_modules", ".tox", ".nox", ".pytest_cache", ".mypy_cache" + } + for root, dirs, files in os.walk(folder_path): + dirs[:] = [ + d for d in dirs + if not d.startswith((".qpypack", "qpypack")) and d not in EXCLUDE_DIR_NAMES + ] + path_obj = Path(root) + if any(p.startswith((".qpypack", "qpypack")) for p in path_obj.parts): continue + if any(part in EXCLUDE_DIR_NAMES for part in path_obj.parts): + continue + for f in files: if f.endswith((".py", ".pyw")): - candidates.append(Path(root) / f) + candidates.append(path_obj / f) if not candidates: self.show_error_log(_("[ERROR] Please load a valid Python source file first!")) @@ -8103,6 +8135,14 @@ class MainWindow(QMainWindow): "Solution:\n1. In Build Settings, switch to [PyInstaller] engine (Recommended).\n2. Or install Visual Studio 2022 with C++ support." ) ) + elif "Problem with the downloaded zip file" in log_content or ("WinError 32" in log_content and "mingw" in log_content.lower()): + msg = ( + "[Environment Error] Nuitka compiler download/extraction failed (WinError 32: File locked by system or antivirus).\n\n" + "Solutions:\n" + "1. Clean damaged cache directory: %LOCALAPPDATA%\\Nuitka\\Nuitka\\Cache\\downloads\n" + "2. Ensure Windows Defender or third-party antivirus is not blocking gcc.exe / zip extraction.\n" + "3. Or switch the build engine to [PyInstaller] in Build Settings." + ) if not success and self.thread and self.thread.params.get("lite_mode") and not getattr(self.thread, "_is_cancelled", False): msg += "\n\n" + _( diff --git a/tests/test_check.py b/tests/test_check.py index bab1a92..d0de236 100644 --- a/tests/test_check.py +++ b/tests/test_check.py @@ -314,6 +314,10 @@ def run_e2e_mock_build(engine_name: str, tmp_dir: Path, is_onefile: bool = True) thread = main.PackingThread(params) results = [] + logs = [] + + # 实时捕获日志 + thread.progress.connect(lambda msg: logs.append(msg)) def on_finished(success, msg, failed_pkgs): results.append((success, msg)) @@ -323,28 +327,30 @@ def run_e2e_mock_build(engine_name: str, tmp_dir: Path, is_onefile: bool = True) assert len(results) > 0, "构建线程未返回结果" success, msg = results[0] + + if not success: + print("\n" + "!" * 30 + " NUITKA ERROR LOGS " + "!" * 30) + print("\n".join(logs)) + print("!" * 79 + "\n") + assert success, f"{engine_name} 构建失败: {msg}" ext = ".exe" if os.name == "nt" else "" if is_onefile: - built_exe = app_dir / f"app_main{ext}" + out_bin = app_dir / f"app_main{ext}" else: - # 针对 文件夹模式 (onedir / standalone) 全面兼容查找路径 - candidates = [ - app_dir / "app_main" / f"app_main{ext}", - app_dir / "app_main.dist" / f"app_main{ext}", - app_dir / f"app_main{ext}", - ] - built_exe = next((p for p in candidates if p.exists()), None) + out_bin = app_dir / "app_main" / f"app_main{ext}" - assert built_exe is not None and built_exe.exists(), f"找不到构建产物,搜索路径: {candidates if not is_onefile else built_exe}" + assert out_bin.exists(), f"未找到生成的二进制可执行文件: {out_bin}" - # 实机拉起产物验证 - proc = subprocess.run([built_exe.as_posix()], capture_output=True, text=True, timeout=10) - assert proc.returncode == 0 - assert "BOOT_SUCCESS_OK" in proc.stdout - log_pass(f"{engine_name} (Lite Mode) 产物实机拉起验证成功!") + # 实机运行验证 + kw = {"capture_output": True, "text": True, "timeout": 10, "errors": "ignore"} + if os.name == "nt": + kw["creationflags"] = subprocess.CREATE_NO_WINDOW + proc = subprocess.run([out_bin.as_posix()], **kw) + assert proc.returncode == 0, f"构建产物启动异常退出,ReturnCode: {proc.returncode}" + assert "BOOT_SUCCESS_OK" in proc.stdout, f"产物输出未匹配到预期签名,标准输出: {proc.stdout}" def test_07_pyinstaller_real_build(init_qapp): """测试 7: PyInstaller 真实构建与产物执行测试"""