From 57b686c84150dac91acfcaf5bbf67d3a7bba7ed4 Mon Sep 17 00:00:00 2001 From: Sceef Date: Thu, 2 Apr 2026 14:59:09 +0700 Subject: [PATCH] fix(packaging): bundle setuptools/_vendor for frozen pkg_resources Setuptools 80+ pkg_resources imports jaraco.* and platformdirs after adding setuptools/_vendor to sys.path. PyInstaller onefile did not ship that tree, causing ModuleNotFoundError: jaraco at pyi_rth_pkgres. Include the full _vendor directory as datas; add platformdirs to hiddenimports. Applied to windows, linux, and macos specs. Made-with: Cursor --- packaging/linux.spec | 9 ++++++++- packaging/macos.spec | 10 +++++++++- packaging/windows.spec | 11 ++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packaging/linux.spec b/packaging/linux.spec index ab27315..9ee5b7a 100644 --- a/packaging/linux.spec +++ b/packaging/linux.spec @@ -10,7 +10,13 @@ block_cipher = None # customtkinter ships JSON themes + assets that must be bundled import customtkinter +import setuptools + ctk_path = os.path.dirname(customtkinter.__file__) +_vendor = os.path.join(os.path.dirname(setuptools.__file__), '_vendor') +_setuptools_vendor = ( + [(_vendor, os.path.join('setuptools', '_vendor'))] + if os.path.isdir(_vendor) else []) # Collect gi (PyGObject) submodules and data so pystray._appindicator works gi_hiddenimports = collect_submodules('gi') @@ -26,7 +32,7 @@ a = Analysis( [os.path.join(os.path.dirname(SPEC), os.pardir, 'linux.py')], pathex=[], binaries=[], - datas=[(ctk_path, 'customtkinter/')] + gi_datas + typelib_datas, + datas=[(ctk_path, 'customtkinter/')] + _setuptools_vendor + gi_datas + typelib_datas, hiddenimports=[ 'pystray._appindicator', 'PIL._tkinter_finder', @@ -35,6 +41,7 @@ a = Analysis( 'cryptography.hazmat.primitives.ciphers.algorithms', 'cryptography.hazmat.primitives.ciphers.modes', 'cryptography.hazmat.backends.openssl', + 'platformdirs', 'gi', '_gi', 'gi.repository.GLib', diff --git a/packaging/macos.spec b/packaging/macos.spec index 5f38945..cd9f132 100644 --- a/packaging/macos.spec +++ b/packaging/macos.spec @@ -5,11 +5,18 @@ import os block_cipher = None +import setuptools + +_vendor = os.path.join(os.path.dirname(setuptools.__file__), '_vendor') +_macos_datas = ( + [(_vendor, os.path.join('setuptools', '_vendor'))] + if os.path.isdir(_vendor) else []) + a = Analysis( [os.path.join(os.path.dirname(SPEC), os.pardir, 'macos.py')], pathex=[], binaries=[], - datas=[], + datas=_macos_datas, hiddenimports=[ 'rumps', 'objc', @@ -21,6 +28,7 @@ a = Analysis( 'cryptography.hazmat.primitives.ciphers.algorithms', 'cryptography.hazmat.primitives.ciphers.modes', 'cryptography.hazmat.backends.openssl', + 'platformdirs', ], hookspath=[], hooksconfig={}, diff --git a/packaging/windows.spec b/packaging/windows.spec index 1c8dd81..cdd810f 100644 --- a/packaging/windows.spec +++ b/packaging/windows.spec @@ -7,13 +7,21 @@ block_cipher = None # customtkinter ships JSON themes + assets that must be bundled import customtkinter +import setuptools + ctk_path = os.path.dirname(customtkinter.__file__) +# pkg_resources (pyi_rth_pkgres) prepends setuptools/_vendor to sys.path and +# imports jaraco.* from there; frozen builds need the tree on disk. +_vendor = os.path.join(os.path.dirname(setuptools.__file__), '_vendor') +_bundle_datas = [(ctk_path, 'customtkinter/')] +if os.path.isdir(_vendor): + _bundle_datas.append((_vendor, os.path.join('setuptools', '_vendor'))) a = Analysis( [os.path.join(os.path.dirname(SPEC), os.pardir, 'windows.py')], pathex=[], binaries=[], - datas=[(ctk_path, 'customtkinter/')], + datas=_bundle_datas, hiddenimports=[ 'pystray._win32', 'PIL._tkinter_finder', @@ -22,6 +30,7 @@ a = Analysis( 'cryptography.hazmat.primitives.ciphers.algorithms', 'cryptography.hazmat.primitives.ciphers.modes', 'cryptography.hazmat.backends.openssl', + 'platformdirs', ], hookspath=[], hooksconfig={},