aggiornato lettore per gestire pacchetti come pygount

This commit is contained in:
VALLONGOL 2025-12-15 10:37:05 +01:00
parent ded49d5ac6
commit 5dcfa797e9
4 changed files with 98 additions and 7 deletions

View File

@ -477,6 +477,9 @@ exe = EXE(
parsed_spec_opts = self._get_last_parsed_spec_options() or {}
final_hiddenimports = list(parsed_spec_opts.get('hiddenimports', []) or [])
# Preserve hookspath and runtime_hooks from existing spec if present
final_hookspath = parsed_spec_opts.get('hookspath', []) or []
final_runtime_hooks = parsed_spec_opts.get('runtime_hooks', []) or []
# Use a user-confirmed list if provided by the GUI; otherwise, optionally
# run the static detector when the option is enabled.
try:
@ -500,6 +503,22 @@ exe = EXE(
self._log_message(f"Dependency detection failed: {e}", level="WARNING")
final_binaries = parsed_spec_opts.get('binaries', [])
# Detect packages that were packaged as wheels/datas which may need collect_all
collect_all_pkgs: List[str] = []
try:
datas_from_spec = parsed_spec_opts.get('datas', []) or []
for d in datas_from_spec:
# datas entries may be tuples like (src, dest)
try:
src = d[0] if isinstance(d, (list, tuple)) and len(d) > 0 else str(d)
except Exception:
src = str(d)
src_lower = str(src).lower()
if 'pygount' in src_lower and 'pygount' not in collect_all_pkgs:
collect_all_pkgs.append('pygount')
except Exception:
pass
analysis_pathex_list = []
if source_dir_rel_path and source_dir_rel_path != ".":
analysis_pathex_list.append(source_dir_rel_path)
@ -511,6 +530,9 @@ exe = EXE(
'formatted_datas': current_datas_for_spec,
'formatted_hiddenimports': final_hiddenimports,
'formatted_binaries': final_binaries,
'formatted_hookspath': final_hookspath,
'formatted_runtime_hooks': final_runtime_hooks,
'collect_all_pkgs': collect_all_pkgs,
'app_name': self._get_app_name(),
'icon_rel_path': icon_rel_path_for_spec,
'is_windowed': self._get_is_windowed(),
@ -574,10 +596,35 @@ exe = EXE(
cipher_var, analysis_var, pyz_var = gui_options_dict['pyz_cipher_var_name'], gui_options_dict['a_var_name'], gui_options_dict['pyz_var_name']
nodes: List[ast.stmt] = [
ast.Expr(value=create_node("\n# PyInstaller spec file generated by GUI Wrapper.\n")),
ast.Assign(targets=[ast.Name(id=cipher_var, ctx=ast.Store())], value=create_node(None)),
ast.Assign(
nodes: List[ast.stmt] = []
# Optional: support injecting collect_all(...) assignments for packages
collect_all_pkgs = gui_options_dict.get('collect_all_pkgs', []) or []
if collect_all_pkgs:
# Add: from PyInstaller.utils.hooks import collect_all
try:
import_node = ast.ImportFrom(module='PyInstaller.utils.hooks', names=[ast.alias(name='collect_all', asname=None)], level=0)
nodes.append(import_node)
except Exception:
pass
for pkg in collect_all_pkgs:
# Create names like _pygount_datas, _pygount_binaries, _pygount_hiddenimports
safe_pkg = pkg.replace('-', '_')
names_tuple = ast.Tuple(elts=[
ast.Name(id=f'_{safe_pkg}_datas', ctx=ast.Store()),
ast.Name(id=f'_{safe_pkg}_binaries', ctx=ast.Store()),
ast.Name(id=f'_{safe_pkg}_hiddenimports', ctx=ast.Store())
], ctx=ast.Store())
call_node = ast.Call(func=ast.Name(id='collect_all', ctx=ast.Load()), args=[ast.Constant(value=pkg)], keywords=[])
assign_node = ast.Assign(targets=[names_tuple], value=call_node)
nodes.append(assign_node)
# Standard leading comment and cipher assignment
nodes.append(ast.Expr(value=create_node("\n# PyInstaller spec file generated by GUI Wrapper.\n")))
nodes.append(ast.Assign(targets=[ast.Name(id=cipher_var, ctx=ast.Store())], value=create_node(None)))
# Build Analysis node
analysis_node = ast.Assign(
targets=[ast.Name(id=analysis_var, ctx=ast.Store())],
value=ast.Call(
func=ast.Name(id='Analysis', ctx=ast.Load()),
@ -589,16 +636,24 @@ exe = EXE(
ast.keyword(arg='binaries', value=create_node(gui_options_dict.get('formatted_binaries',[]))),
ast.keyword(arg='datas', value=create_node(gui_options_dict.get('formatted_datas', []))),
ast.keyword(arg='hiddenimports', value=create_node(gui_options_dict.get('formatted_hiddenimports',[]))),
ast.keyword(arg='hookspath', value=create_node([])),
ast.keyword(arg='hookspath', value=create_node(gui_options_dict.get('formatted_hookspath', []))),
ast.keyword(arg='hooksconfig', value=ast.Dict(keys=[], values=[])),
ast.keyword(arg='runtime_hooks', value=create_node([])),
ast.keyword(arg='runtime_hooks', value=create_node(gui_options_dict.get('formatted_runtime_hooks', []))),
ast.keyword(arg='excludes', value=create_node([])),
ast.keyword(arg='win_no_prefer_redirects', value=create_node(False)),
ast.keyword(arg='win_private_assemblies', value=create_node(False)),
ast.keyword(arg='cipher', value=ast.Name(id=cipher_var, ctx=ast.Load())),
ast.keyword(arg='noarchive', value=create_node(False))
]))
]
nodes.append(analysis_node)
# If we injected collect_all assignments, append try/except blocks to add hiddenimports to 'a'
if collect_all_pkgs:
for pkg in collect_all_pkgs:
safe_pkg = pkg.replace('-', '_')
aug = ast.AugAssign(target=ast.Attribute(value=ast.Name(id='a', ctx=ast.Load()), attr='hiddenimports', ctx=ast.Store()), op=ast.Add(), value=ast.Name(id=f'_{safe_pkg}_hiddenimports', ctx=ast.Load()))
try_node = ast.Try(body=[aug], handlers=[ast.ExceptHandler(type=None, name=None, body=[ast.Pass()])], orelse=[], finalbody=[])
nodes.append(try_node)
nodes.append(ast.Assign(
targets=[ast.Name(id=pyz_var, ctx=ast.Store())],
value=ast.Call(

View File

@ -58,6 +58,16 @@ class SpecEditorPanel(ttk.Frame):
# Do an initial silent refresh (do not show messageboxes when no spec)
self.refresh_calls(silent=True)
# Bind combobox selection to auto-refresh keywords list (no need to click Refresh)
try:
self.call_select.bind('<<ComboboxSelected>>', lambda e: self.refresh_calls())
except Exception:
pass
# Bind listbox selection to auto-load keyword when user selects an entry
try:
self.keywords_listbox.bind('<<ListboxSelect>>', lambda e: self.load_selected_keyword())
except Exception:
pass
def _log(self, msg: str, level: str = 'INFO'):
try:

View File

@ -141,6 +141,9 @@ class _SpecVisitor(ast.NodeVisitor):
self.parsed_options["pathex"] = positional_args[1] or []
self.parsed_options["datas"] = options.get("datas", [])
self.parsed_options["hiddenimports"] = options.get("hiddenimports", [])
# Capture optional hookspath and runtime_hooks if present in Analysis
self.parsed_options["hookspath"] = options.get("hookspath", [])
self.parsed_options["runtime_hooks"] = options.get("runtime_hooks", [])
self.parsed_options["binaries"] = options.get("binaries", [])
elif call_name == "EXE":
self._log(f"Found EXE() call.")

23
pyucc.spec Normal file
View File

@ -0,0 +1,23 @@
from PyInstaller.utils.hooks import collect_all
# Ensure pygount package contents are explicitly collected (datas, binaries, hiddenimports)
_pygount_datas, _pygount_binaries, _pygount_hiddenimports = collect_all('pygount')
block_cipher = None
a = Analysis(pathex=['pyucc', '.'], binaries=[], datas=[('pyucc/_internal/pygount-3.0.0-py3-none-any.whl', '_internal'),('PyUcc.ico', '.'), ('external\\python-tkinter-logger\\tkinter_logger.py', '.'), ('external\\python-resource-monitor\\resource_monitor.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('wheels\\pygount-3.1.0-py3-none-any.whl', 'pyucc\\_internal')], hiddenimports=['tkinter_logger', 'resource_monitor', 'pyucc.core.differ', 'pyucc.gui.gui', 'pyucc.config.settings', 'logging', 'logging.handlers', 'logging.config', 'ConfigParser', 'Cython', 'HTMLParser', 'IPython', 'OpenSSL', 'PIL', 'Queue', 'StringIO', 'android', 'annotationlib', 'argcomplete', 'attr', 'autocommand', 'backports', 'cgi', 'chardet', 'colorama', 'contextlib2', 'cryptography', 'ctags', 'distutils', 'dl', 'docutils', 'dummy_thread', 'dummy_threading', 'exceptiongroup', 'fcntl', 'filelock', 'future_builtins', 'git', 'gitdb', 'gitdb_speedups', 'google', 'grp', 'htmlentitydefs', 'httplib', 'importlib_metadata', 'importlib_resources', 'inflect', 'ini2toml', 'iniconfig', 'ipywidgets', 'jaraco', 'java', 'jinja2', 'jnius', 'keyring', 'linkify_it', 'lizard', 'lizard_ext', 'lizard_languages', 'markdown_it', 'mdurl', 'mock', 'mod', 'mod2', 'more_itertools', 'nspkg', 'ntlm', 'numpy', 'packaging', 'path', 'pathspec', 'pexpect', 'pip', 'pkg1', 'pkg_resources', 'platformdirs', 'pluggy', 'psutil', 'pwd', 'py', 'pygments', 'pygount', 'pytest', 'pyucc', 'pywintypes', 'readline', 'redis', 'resource', 'rich', 'setuptools', 'sha', 'smmap', 'socks', 'sphinx', 'target_simulator', 'thread', 'tomli', 'tomli_w', 'trove_classifiers', 'twisted', 'typeguard', 'typeshed', 'typing_extensions', 'urllib2', 'urllib3_secure_extra', 'urlparse', 'wheel', 'win32api', 'win32con', 'win32process', 'wmi', 'xmlrpclib', 'xx', 'zipp', 'zope', 'traitlets', 'gdb', 'matplotlib', 'PyInstaller'], hookspath=['hooks'], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, scripts=['pyucc\\__main__.py'])
try:
a.hiddenimports += _pygount_hiddenimports
except Exception:
pass
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='PyUcc', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=False, icon='PyUcc.ico', exclude_binaries=True)
coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='PyUcc')
block_cipher = None
a = Analysis(pathex=['pyucc', '.'], binaries=[], datas=[('pyucc/_internal/pygount-3.0.0-py3-none-any.whl', '_internal'),('PyUcc.ico', '.'), ('external\\python-tkinter-logger\\tkinter_logger.py', '.'), ('external\\python-resource-monitor\\resource_monitor.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger'), ('external\\_setup_paths.py', '.'), ('external\\python-resource-monitor', 'python-resource-monitor'), ('external\\python-tkinter-logger', 'python-tkinter-logger')], hiddenimports=['tkinter_logger', 'resource_monitor', 'pyucc.core.differ', 'pyucc.gui.gui', 'pyucc.config.settings', 'logging', 'logging.handlers', 'logging.config', 'ConfigParser', 'Cython', 'HTMLParser', 'IPython', 'OpenSSL', 'PIL', 'Queue', 'StringIO', 'android', 'annotationlib', 'argcomplete', 'attr', 'autocommand', 'backports', 'cgi', 'chardet', 'colorama', 'contextlib2', 'cryptography', 'ctags', 'distutils', 'dl', 'docutils', 'dummy_thread', 'dummy_threading', 'exceptiongroup', 'fcntl', 'filelock', 'future_builtins', 'git', 'gitdb', 'gitdb_speedups', 'google', 'grp', 'htmlentitydefs', 'httplib', 'importlib_metadata', 'importlib_resources', 'inflect', 'ini2toml', 'iniconfig', 'ipywidgets', 'jaraco', 'java', 'jinja2', 'jnius', 'keyring', 'linkify_it', 'lizard', 'lizard_ext', 'lizard_languages', 'markdown_it', 'mdurl', 'mock', 'mod', 'mod2', 'more_itertools', 'nspkg', 'ntlm', 'numpy', 'packaging', 'path', 'pathspec', 'pexpect', 'pip', 'pkg1', 'pkg_resources', 'platformdirs', 'pluggy', 'psutil', 'pwd', 'py', 'pygments', 'pygount', 'pytest', 'pyucc', 'pywintypes', 'readline', 'redis', 'resource', 'rich', 'setuptools', 'sha', 'smmap', 'socks', 'sphinx', 'target_simulator', 'thread', 'tomli', 'tomli_w', 'trove_classifiers', 'twisted', 'typeguard', 'typeshed', 'typing_extensions', 'urllib2', 'urllib3_secure_extra', 'urlparse', 'wheel', 'win32api', 'win32con', 'win32process', 'wmi', 'xmlrpclib', 'xx', 'zipp', 'zope', 'traitlets', 'gdb', 'matplotlib', 'PyInstaller'], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, scripts=['pyucc\\__main__.py'])
try:
a.hiddenimports += _pygount_hiddenimports
except Exception:
pass
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='PyUcc', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=False, icon='PyUcc.ico', exclude_binaries=True)
coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='PyUcc')