Repository: pyinstaller/pyinstaller

Issue:
Could not find Info.plist for PyQt 5.10 using PyInstaller 6.0 on macOS
## Description of the issue

While freezing a program using `PyQt 5.10` using `PyInstaller 6.0` on `OS X 10.11.6`, the following error occurs: 
```
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 209, in <module>
    run()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 189, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 61, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 1033, in main
    build(specfile, distpath, workpath, clean_build)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 973, in build
    exec(code, spec_namespace)
  File "wl_packaging.spec", line 117, in <module>
    a = Analysis(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 466, in __init__
    self.__postinit__()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/datastruct.py", line 184, in __postinit__
    self.assemble()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 809, in assemble
    combined_toc += osxutils.collect_files_from_framework_bundles(combined_toc)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/osx.py", line 605, in collect_files_from_framework_bundles
    raise SystemError(
SystemError: Could not find Info.plist file for .framework bundle in /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyQt5/Qt/lib/QtWidgets.framework/Versions/5/Resources/Info.plist or /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyQt5/Qt/lib/QtWidgets.framework/Resources/Info.plist!
```

### Context information (for bug reports)

* Output of `pyinstaller --version`: ```6.0.0```
* Version of Python: <!-- e.g. 3.11 -->3.10.11
* Platform: <!-- e.g GNU/Linux (distribution), Windows (language settings), OS X, FreeBSD -->OS X 10.11.6
* How you installed Python: <!-- e.g. python.org/downloads, conda, brew, pyenv, apt, Windows store -->python.org/downloads
* Did you also try this on another platform? Does it work there?
Works on Windows, but not relevant I suppose.

* try the latest development version, using the following command:

```shell
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
```
6.0.0 is already the latest development version.

* follow *all* the instructions in our "If Things Go Wrong" Guide
  (https://github.com/pyinstaller/pyinstaller/wiki/If-Things-Go-Wrong) and

### Make sure [everything is packaged correctly](https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs#make-sure-everything-is-packaged-correctly)

  * [x] start with clean installation
  * [x] use the latest development version
  * [x] Run your frozen program **from a command window (shell)** — instead of double-clicking on it
  * [x] Package your program in **--onedir mode**
  * [x] Package **without UPX**, say: use the option `--noupx` or set `upx=False` in your .spec-file
  * [x] Repackage you application in **verbose/debug mode**. For this, pass the option `--debug` to `pyi-makespec` or `pyinstaller` or use `EXE(..., debug=1, ...)` in your .spec file.


### A minimal example program which shows the error

```
from PyQt5 import QtWidgets
```

### Stacktrace / full error message


```
371 INFO: PyInstaller: 6.0.0
371 INFO: Python: 3.10.11
387 INFO: Platform: macOS-10.11.6-x86_64-i386-64bit
390 INFO: wrote /Users/blkserene/Desktop/test.spec
414 INFO: Extending PYTHONPATH with paths
['/Users/blkserene/Desktop']
796 INFO: checking Analysis
797 INFO: Building Analysis because Analysis-00.toc is non existent
798 INFO: Initializing module dependency graph...
803 INFO: Caching module graph hooks...
839 INFO: Analyzing base_library.zip ...
1392 INFO: Loading module hook 'hook-heapq.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
1449 INFO: Loading module hook 'hook-encodings.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
2544 INFO: Loading module hook 'hook-pickle.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
3309 INFO: Caching module dependency graph...
3382 INFO: Running Analysis Analysis-00.toc
3382 INFO: Looking for Python shared library...
3387 INFO: Using Python shared library: /Library/Frameworks/Python.framework/Versions/3.10/Python
3387 INFO: Analyzing /Users/blkserene/Desktop/test.py
3388 INFO: Processing module hooks...
3393 INFO: Loading module hook 'hook-PyQt5.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
3539 WARNING: Hidden import "PyQt5.sip" not found!
3589 INFO: Looking for ctypes DLLs
3592 INFO: Analyzing run-time hooks ...
3594 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py'
3595 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5.py'
3597 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py'
3602 INFO: Looking for dynamic libraries
3848 INFO: Warnings written to /Users/blkserene/Desktop/build/test/warn-test.txt
3857 INFO: Graph cross-reference written to /Users/blkserene/Desktop/build/test/xref-test.html
3869 INFO: checking PYZ
3869 INFO: Building PYZ because PYZ-00.toc is non existent
3870 INFO: Building PYZ (ZlibArchive) /Users/blkserene/Desktop/build/test/PYZ-00.pyz
3998 INFO: Building PYZ (ZlibArchive) /Users/blkserene/Desktop/build/test/PYZ-00.pyz completed successfully.
4001 INFO: EXE target arch: x86_64
4001 INFO: Code signing identity: None
4004 INFO: checking PKG
4004 INFO: Building PKG because PKG-00.toc is non existent
4004 INFO: Building PKG (CArchive) test.pkg
4009 INFO: Building PKG (CArchive) test.pkg completed successfully.
4010 INFO: Bootloader /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/bootloader/Darwin-64bit/run
4011 INFO: checking EXE
4011 INFO: Building EXE because EXE-00.toc is non existent
4011 INFO: Building EXE from EXE-00.toc
4012 INFO: Copying bootloader EXE to /Users/blkserene/Desktop/build/test/test
4013 INFO: Converting EXE to target arch (x86_64)
4015 INFO: Removing signature(s) from EXE
4015 INFO: Appending PKG archive to EXE
4017 INFO: Fixing EXE headers for code signing
4026 INFO: Re-signing the EXE
4080 INFO: Building EXE from EXE-00.toc completed successfully.
4083 INFO: checking COLLECT
4083 INFO: Building COLLECT because COLLECT-00.toc is non existent
4083 INFO: Building COLLECT COLLECT-00.toc
7936 INFO: Building COLLECT COLLECT-00.toc completed successfully.
BLKSerenes-Mac:Desktop blkserene$ pyinstaller test.py
186 INFO: PyInstaller: 6.0.0
186 INFO: Python: 3.10.11
194 INFO: Platform: macOS-10.11.6-x86_64-i386-64bit
195 INFO: wrote /Users/blkserene/Desktop/test.spec
198 INFO: Extending PYTHONPATH with paths
['/Users/blkserene/Desktop']
396 INFO: checking Analysis
398 INFO: Building because /Users/blkserene/Desktop/test.py changed
398 INFO: Initializing module dependency graph...
399 INFO: Caching module graph hooks...
407 INFO: Analyzing base_library.zip ...
929 INFO: Loading module hook 'hook-heapq.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
978 INFO: Loading module hook 'hook-encodings.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
1938 INFO: Loading module hook 'hook-pickle.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
2755 INFO: Caching module dependency graph...
2827 INFO: Running Analysis Analysis-00.toc
2827 INFO: Looking for Python shared library...
2831 INFO: Using Python shared library: /Library/Frameworks/Python.framework/Versions/3.10/Python
2831 INFO: Analyzing /Users/blkserene/Desktop/test.py
2832 INFO: Processing module hooks...
2836 INFO: Loading module hook 'hook-PyQt5.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
2923 WARNING: Hidden import "PyQt5.sip" not found!
2950 INFO: Loading module hook 'hook-PyQt5.QtWidgets.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
3044 INFO: Loading module hook 'hook-PyQt5.QtCore.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
3133 INFO: Loading module hook 'hook-PyQt5.QtGui.py' from '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks'...
3344 INFO: Looking for ctypes DLLs
3347 INFO: Analyzing run-time hooks ...
3349 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py'
3351 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5.py'
3352 INFO: Including run-time hook '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py'
3358 INFO: Looking for dynamic libraries
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/bin/pyinstaller", line 8, in <module>
    sys.exit(_console_script_run())
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 205, in _console_script_run
    run()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 189, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/__main__.py", line 61, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 1033, in main
    build(specfile, distpath, workpath, clean_build)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 973, in build
    exec(code, spec_namespace)
  File "/Users/blkserene/Desktop/test.spec", line 4, in <module>
    a = Analysis(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 466, in __init__
    self.__postinit__()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/datastruct.py", line 184, in __postinit__
    self.assemble()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 809, in assemble
    combined_toc += osxutils.collect_files_from_framework_bundles(combined_toc)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/osx.py", line 605, in collect_files_from_framework_bundles
    raise SystemError(
SystemError: Could not find Info.plist file for .framework bundle in /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyQt5/Qt/lib/QtWidgets.framework/Versions/5/Resources/Info.plist or /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyQt5/Qt/lib/QtWidgets.framework/Resources/Info.plist!
```

Please also see <https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs>
for more about what would use to solve the issue.



Discussion:
Looks like PyQt 5.10 does indeed not provide the `Info.plist` files with its Qt .framework bundles. Which, strictly speaking, makes those bundles invalid as per Apple's .framework bundle specifications. And it looks like they started including them starting with PyQt 5.14.1.

We could demote that error into a warning, but if you are generating an .app bundle, it will not be signable due to invalid structure (of the nested Qt .framework bundles). Signing issues aside, it should probably work (as should the regular onedir build).

But either way, is there a particular reason you are using PyQt 5.10? Why not go to the latest 5.15.x?
I'm building on OS X 10.11, and the latest version of `PyQt` supporting OS X 10.11 is 5.10.

It's okay if the bundle is not signable, since codesign functionalities do not work properly on OS X 10.11 and in fact I need to comment out some codesign-related lines in the source codes (in addition to re-compiling the bootloader to re-target OS X 10.11).

The hacks work until `PyInstaller 5.13.2`, and I'm still figuring out how to solve the issues with `PyInstaller 6.0`...
For the `Info.plist` issue, you should replace this exception
https://github.com/pyinstaller/pyinstaller/blob/e70c723d8166c0c28f19bc3f0f3da3c814cc061c/PyInstaller/utils/osx.py#L605-L607
with a `continue`.
@rokm Thanks! I was commenting out the exception and that triggered other issues... `continue` works.

Resolving patch:
diff --git a/PyInstaller/utils/osx.py b/PyInstaller/utils/osx.py
--- a/PyInstaller/utils/osx.py
+++ b/PyInstaller/utils/osx.py
@@ -37,7 +37,7 @@
 import macholib.util
 
 import PyInstaller.log as logging
-from PyInstaller.compat import base_prefix
+from PyInstaller import compat
 
 logger = logging.getLogger(__name__)
 
@@ -50,7 +50,7 @@ def is_homebrew_env():
     """
     # Python path prefix should start with Homebrew prefix.
     env_prefix = get_homebrew_prefix()
-    if env_prefix and base_prefix.startswith(env_prefix):
+    if env_prefix and compat.base_prefix.startswith(env_prefix):
         return True
     return False
 
@@ -63,7 +63,7 @@ def is_macports_env():
     """
     # Python path prefix should start with Macports prefix.
     env_prefix = get_macports_prefix()
-    if env_prefix and base_prefix.startswith(env_prefix):
+    if env_prefix and compat.base_prefix.startswith(env_prefix):
         return True
     return False
 
@@ -571,6 +571,8 @@ def collect_files_from_framework_bundles(collected_files):
     Returns TOC list for the discovered Info.plist files and generated symbolic links. The list does not contain
     duplicated entries.
     """
+    invalid_framework_found = False
+
     framework_files = set()  # Additional entries for collected files. Use set for de-duplication.
     framework_paths = set()  # Registered framework paths for 2nd pass.
 
@@ -602,9 +604,18 @@ def collect_files_from_framework_bundles(collected_files):
             # versioned directory to appease the code-signing gods...
             info_plist_src_top = src_path.parent.parent.parent / "Resources" / "Info.plist"
             if not info_plist_src_top.is_file():
-                raise SystemError(
-                    f"Could not find Info.plist file for .framework bundle in {info_plist_src} or {info_plist_src_top}!"
-                )
+                # Strictly speaking, a .framework bundle without Info.plist is invalid. However, that did not prevent
+                # PyQt from shipping such Qt .framework bundles up until v5.14.1. So by default, we just complain via
+                # a warning message; if such binaries work in unfrozen python, they should also work in frozen
+                # application. The codesign will refuse to sign the .app bundle (if we are generating one), but there
+                # is nothing we can do about that.
+                invalid_framework_found = True
+                framework_dir = src_path.parent.parent.parent
+                if compat.strict_collect_mode:
+                    raise SystemError(f"Could not find Info.plist in {framework_dir}!")
+                else:
+                    logger.warning("Could not find Info.plist in %s!", framework_dir)
+                    continue
             info_plist_src = info_plist_src_top
         info_plist_dest = dest_path.parent / "Resources" / "Info.plist"
         framework_files.add((str(info_plist_dest), str(info_plist_src), "DATA"))
@@ -665,4 +676,12 @@ def collect_files_from_framework_bundles(collected_files):
                 "SYMLINK",
             ))
 
+    # If we encountered an invalid .framework bundle without Info.plist, warn the user that code-signing will most
+    # likely fail.
+    if invalid_framework_found:
+        logger.warning(
+            "One or more collected .framework bundles have missing Info.plist file. If you are building an .app "
+            "bundle, you will most likely not be able to code-sign it."
+        )
+
     return sorted(framework_files)


Test patch: