Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception: Qt plugin directory '*/test/venv/lib/site-packages/PySide6/plugins' does not exist! #7385

Closed
6 tasks
youjunxiaji opened this issue Jan 20, 2023 · 9 comments

Comments

@youjunxiaji
Copy link

Description of the issue

Context information (for bug reports)

  • Output of pyinstaller --version: 5.7.0

  • Version of Python: 3.9.5

  • Platform: Windows (CN)

  • How you installed Python: python.org/downloads

  • Did you also try this on another platform? Does it work there?
    yes ,i try to run in base ,it works.

  • try the latest development version, using the following command:

pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip

Make sure everything is packaged correctly

  • start with clean installation
  • use the latest development version
  • Run your frozen program from a command window (shell) — instead of double-clicking on it
  • Package your program in --onedir mode
  • Package without UPX, say: use the option --noupx or set upx=False in your .spec-file
  • 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.

Stacktrace / full error message

Traceback (most recent call last):
  File "D:\python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "D:\python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "E:\桌面\test\venv\Scripts\pyinstaller.exe\__main__.py", line 7, in <module>
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\__main__.py", line 194, in _console_script_run
    run()
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\__main__.py", line 180, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\__main__.py", line 61, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\building\build_main.py", line 971, in main
    build(specfile, distpath, workpath, clean_build)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\building\build_main.py", line 893, in build
    exec(code, spec_namespace)
  File "E:\桌面\test\main.spec", line 7, in <module>
    a = Analysis(
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\building\build_main.py", line 411, in __init__
    self.__postinit__()
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\building\datastruct.py", line 173, in __postinit__       
    self.assemble()
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\building\build_main.py", line 580, in assemble
    self.graph.process_post_graph_hooks(self)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\depend\analysis.py", line 330, in process_post_graph_hooks
    module_hook.post_graph(analysis)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\depend\imphook.py", line 447, in post_graph
    self._load_hook_module(keep_module_ref=True)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\depend\imphook.py", line 387, in _load_hook_module       
    self._hook_module = importlib_load_source(self.hook_module_name, self.hook_filename)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\compat.py", line 612, in importlib_load_source
    return mod_loader.load_module()
  File "<frozen importlib._bootstrap_external>", line 529, in _check_name_wrapper
  File "<frozen importlib._bootstrap_external>", line 1034, in load_module
  File "<frozen importlib._bootstrap_external>", line 859, in load_module
  File "<frozen importlib._bootstrap>", line 274, in _load_module_shim
  File "<frozen importlib._bootstrap>", line 711, in _load
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 855, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\hooks\hook-PySide6.QtNetwork.py", line 14, in <module>   
    hiddenimports, binaries, datas = add_qt6_dependencies(__file__)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\utils\hooks\qt\__init__.py", line 832, in add_qt_dependencies
    return qt_info.collect_module(module_name)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\utils\hooks\qt\__init__.py", line 416, in collect_module 
    binaries += self.collect_plugins(plugin_type)
  File "e:\桌面\test\venv\lib\site-packages\PyInstaller\utils\hooks\qt\__init__.py", line 480, in collect_plugins
    raise Exception(f"Qt plugin directory '{plugin_src_dir}' does not exist!")
Exception: Qt plugin directory 'E:/����/test/venv/lib/site-packages/PySide6/plugins' does not exist!

Please also see https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs
for more about what would use to solve the issue.

@youjunxiaji youjunxiaji added the triage Please triage and relabel this issue label Jan 20, 2023
@rokm
Copy link
Member

rokm commented Jan 20, 2023

Does e:\桌面\test\venv\lib\site-packages\PySide6\plugins actually exist (and the issue comes down to the Chinese characters in the path) or not? If not, what are the contents of the PySide6 directory, and how did you install PySide6?

@rokm
Copy link
Member

rokm commented Jan 20, 2023

Nevermind, looks like characters/encoding issue after all.

Similar problem arises if I put a venv in a path that contains characters from my local alphabet (ščž):

>>> import os
>>> from PyInstaller.utils.hooks import qt
>>> qt.pyside6_library_info.location['PluginsPath']
'C:/Users/Rok/Development/test/�c�/venv/lib/site-packages/PySide6/plugins'
>>> os.path.exists(qt.pyside6_library_info.location['PluginsPath'])
False

@rokm rokm added bug and removed triage Please triage and relabel this issue labels Jan 20, 2023
@youjunxiaji
Copy link
Author

Nevermind, looks like characters/encoding issue after all.

Similar problem arises if I put a venv in a path that contains characters from my local alphabet (ščž):

thank you,i have solved this problem.It is really caused by the encoding.

@bwoodsend
Copy link
Member

PyInstaller shouldn't barf over unicode paths so I'll keep this open.

@rokm
Copy link
Member

rokm commented Jan 20, 2023

PyInstaller shouldn't barf over unicode paths so I'll keep this open.

True, but this particular problem seems to be coming from Qt itself:

import importlib
import sys

modname = sys.argv[1]
QtCore = importlib.import_module(modname + ".QtCore")

# Display plugins' path
if modname in ("PyQt6", "PySide6"):
    plugins_path = QtCore.QLibraryInfo.path(QtCore.QLibraryInfo.LibraryPath.PluginsPath)
else:
    plugins_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.LibraryLocation.PluginsPath)
print(plugins_path)

# Display current working directory
print(QtCore.QFileInfo('.').absoluteFilePath())
(venv) C:\Users\Rok\Development\test\ščž>python program.py PySide2
C:/Users/Rok/Development/test/???/venv/lib/site-packages/PySide2/plugins
C:/Users/Rok/Development/test/ščž

(venv) C:\Users\Rok\Development\test\ščž>python program.py PyQt5
C:/Users/Rok/Development/test/�c�/venv/lib/site-packages/PyQt5/Qt5/plugins
C:/Users/Rok/Development/test/ščž

(venv) C:\Users\Rok\Development\test\ščž>python program.py PySide6
C:/Users/Rok/Development/test/�c�/venv/lib/site-packages/PySide6/plugins
C:/Users/Rok/Development/test/ščž

(venv) C:\Users\Rok\Development\test\ščž>python program.py PyQt6
C:/Users/Rok/Development/test/�c�/venv/lib/site-packages/PyQt6/Qt6/plugins
C:/Users/Rok/Development/test/ščž

@rokm
Copy link
Member

rokm commented Jan 20, 2023

I'll see if I can pinpoint where the mangling occurs in the Qt.

But if the problem is there, we should probably try to work around it on our side:

  1. use our own qt_rel_dir and for example plugins path to determine whether the Qt libs are bundled inside the python package (as they are in PyPI wheels, but are not, for example, in conda or homebrew).
  2. If they are, we can compare the plugins path prefix to __file__ or __paths__[0] attribute; if there is mismatch, assume that the Qt-provided paths are mangled
  3. If we have mangled paths, translate all those locations/paths that are obtained from QLibraryInfo from the mangled prefix onto the __file__/__paths__[0] prefix (which should be OK).

@bwoodsend
Copy link
Member

Hmm, I see. Probably ought to report the print(QtCore.QFileInfo('.').absoluteFilePath()) reproducer to Qt then...

@rokm
Copy link
Member

rokm commented Jan 24, 2023

Turns out the problem is not in the Qt per-se either, but rather in the PySide and PyQt bindings.

Both bindings, upon being loaded, generate an embedded :/qt/etc/qt.conf resource, in which they set the prefix path for the bundled Qt libraries, based on the python package's location. (And the QLibraryInfo code looks for this embedded resource to populate its paths/locations).

The problem is, they use local 8-bit encoding (QString::toLocal8Bit) to store the path (e.g., here), whereas the QSettings implementation in Qt6 (which is used to load the qt.conf) assumes that the values are in UTF8. Therefore, if the package path contains non-ASCII characters, paths returned by QLibraryInfo::path end up mangled due to encoding mismatch. This happens only on Windows; on Linux and macOS, QString::toLocal8Bit is equivalent to QString::toUtf8...

I've opened PYSIDE-2204 with PySide and sent an email to PyQt mailing list.

But there's more to this story. While in Qt6 QSettings assumes that the config values are in UTF8 and the bindings store them using incorrect encoding (meaning the bug can be fixed), in Qt5, the assumed encoding is Latin1. Which means there's no way for PySide2 and PyQt5 to support non-ASCII characters in paths (see PYSIDE-972).

And while we can work around these path encoding issues while building the application (e.g., to avoid the error in the OP), the same problem also affects the run-time. I.e., if a frozen application is placed in a location that contains non-ASCII characters, the Qt plugins will likely fail to be discovered and loaded due to mangled path (for PySide2/PyQt5 on all OSes, for PySide6/PyQt6 on Windows).

@rokm rokm added not-our-bug and removed bug labels Jan 24, 2023
@rokm
Copy link
Member

rokm commented Feb 5, 2023

PYSIDE-2204 has been fixed, so the issue should be fixed in upcoming PySide6 6.5.0 and 6.4.3 releases. Similarly, PyQt6 will have a fix in the upcoming 6.4.2 release. This will fix non-ASCII paths both at build-time and at frozen application's run-time.

As mentioned in above comment, PySide2 and PyQt5 cannot be fixed due to encoding-related limitation in Qt5 itself.

While we could work around the problem for build-time for earlier PySide6/PyQt6 and for all PySide2/PyQt5 versions (by restoring un-mangled paths from python package's path), I don't think it is really worth the hassle, because:

  • in environments with problematic paths, the unfrozen Qt-based python code will run into same issues (unless they happen to use codepaths where no plugins are used)
  • even if we work around the problem at build-time, it will still affect frozen application at run-time (where we can do nothing about it)

So for consistency sake and to prevent further confusion regarding the behavior, it seems better to leave things as-is.

@rokm rokm closed this as not planned Won't fix, can't repro, duplicate, stale Feb 5, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants