Skip to content

Instantly share code, notes, and snippets.

@emendir
Last active July 23, 2024 06:11
Show Gist options
  • Save emendir/b2a2d4e9b2b945596075237548e50850 to your computer and use it in GitHub Desktop.
Save emendir/b2a2d4e9b2b945596075237548e50850 to your computer and use it in GitHub Desktop.
PyQt5 & Kvantum Themes in Python Virtual Environment

PyQt5 & Kvantum Themes in Python Virtual Environment

Problem

Kvantum is a useful theme manager to style the themes of any Qt Apps without touching their code. When running a PyQt5 application from source using my OS' python installation, the kvantum theme is applied correctly. However, when using a python virtual environment, it isn't, producing the following error:

QApplication: invalid style override 'kvantum' passed, ignoring it.

Manual Solution

For the full automation of the solution explained here, see the section below.

The solution for this is to set the QT_PLUGIN_PATH environment variable to both the OS' python installation's PyQt5 plugin directory as well as that of my python virtual environment:

PYTHON_VENV_PATH=/path/to/my/virtual/python/environment

# PyQt5 plugin directories
PLUGIN_DIR_OS="/usr/lib/x86_64-linux-gnu/qt5/plugins"
PLUGIN_DIR_VENV="$PYTHON_VENV_PATH/lib/python3.12/site-packages/PyQt5/Qt5/plugins"

export QT_PLUGIN_PATH=$PLUGIN_DIR_VENV:$PLUGIN_DIR_OS

Also, setting the LD_LIBRARY_PATH is sometimes needed to be able to run PyQt5 apps in a virtual environment at all, to avoid a Cannot mix incompatible Qt library error.

if [ -z $LD_LIBRARY_PATH ];then
    # if LD_LIBRARY_PATH isn't set, set it to our virtualenv's Qt5 lib directory
    export LD_LIBRARY_PATH="$PYTHON_VENV_PATH/lib/python3.12/site-packages/PyQt5/Qt5/lib"
else
    # if LD_LIBRARY_PATH is alreader set, prepend our virtualenv's Qt5 lib directory
    export LD_LIBRARY_PATH="$PYTHON_VENV_PATH/lib/python3.12/site-packages/PyQt5/Qt5/lib:$LD_LIBRARY_PATH"
fi

To test, reload your virtual environment's activation script:

activation_script=$PYTHON_VENV_PATH/bin/activate
source $activation_script
# Run a super-simple PyQt5 application:
python -c 'from PyQt5.QtWidgets import QApplication, QLabel;import sys;app = QApplication(sys.argv);window = QLabel("Hello there!");window.showFullScreen();app.exec()'

To avoid manually setting these environment variables every time you want to run a PyQt5 application, you can add it to your virtual environment's activation script (which depends on the shell you use). In the case of bash:

echo "
export QT_PLUGIN_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/plugins:/usr/lib/x86_64-linux-gnu/qt5/plugins
if [ -z \$LD_LIBRARY_PATH ]; then
    # if LD_LIBRARY_PATH isn't set, set it to our virtualenv's Qt5 lib directory
    export LD_LIBRARY_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/lib
else
    # if LD_LIBRARY_PATH is already set, prepend our virtualenv's Qt5 lib directory
    export LD_LIBRARY_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/lib:\$LD_LIBRARY_PATH
fi
" >> $activation_script

For other shells (e.g. zsh, fish etc.) the above steps must be adapted for the shell language syntax for setting environment variables and the appropriate activation script in activation_script=$PYTHON_VENV_PATH/bin/.

Automated Solution

Below is a shell script that automates the above procedures for bash, including the creation of a virtual environment and installation of pyqt5 if that's not done yet (but it's safe to run on an existing virtual environment folder).

The script takes the python virtual environment's directory as an argument, so run it like so:

create_pyqt5_venv.sh /tmp/venv

Then test:

source /tmp/venv/bin/activate
# Run a super-simple PyQt5 application:
python -c 'from PyQt5.QtWidgets import QApplication, QLabel;import sys;app = QApplication(sys.argv);window = QLabel("Hello there!");window.showFullScreen();app.exec()'

For other shells (e.g. zsh, fish etc.) the script still needs to be expanded, taking care of the shell language syntax for setting environment variables and the appropriate activation script in activation_script=$PYTHON_VENV_PATH/bin/.

Tested On

  • OS: Ubuntu 24.04 LTS 64-bit
  • Python: 3.12.3
  • PyQt5: 5.15.11
#!/bin/bash
## This script configures a python virtual environment to apply themes from the
## Kvantum theme manager to PyQt5 apps, and fixes another PyQt5 bug.
## Limitations: Currently only built for bash, but should be easy enough to
## expand to support other shells.
## See the documentation for more details:
## https://gist.github.com/emendir/b2a2d4e9b2b945596075237548e50850
PYTHON_VENV_PATH=$1
activation_script=$PYTHON_VENV_PATH/bin/activate
if [ -z $PYTHON_VENV_PATH ];then
echo "Specify a valid directory for the Python virtual environment!"
exit 1
fi
# create python virtual environment if it isn't already
if [ -f $activation_script ];then
echo "Virtual environment already exists in that path, skipping creation."
else
virtualenv $PYTHON_VENV_PATH
fi
# assert that virtual environment was created
if ! [ -f $activation_script ];then
echo "Creation of virtual environment failed."
exit 1
fi
# install pyqt5
source $activation_script
pip install pyqt5
# Configure the virtual environment's bash script
sh_code="
export QT_PLUGIN_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/plugins:/usr/lib/x86_64-linux-gnu/qt5/plugins
if [ -z \$LD_LIBRARY_PATH ]; then
# if LD_LIBRARY_PATH isn't set, set it to our virtualenv's Qt5 lib directory
export LD_LIBRARY_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/lib
else
# if LD_LIBRARY_PATH is already set, prepend our virtualenv's Qt5 lib directory
export LD_LIBRARY_PATH=${PYTHON_VENV_PATH}/lib/python3.12/site-packages/PyQt5/Qt5/lib:\$LD_LIBRARY_PATH
fi
"
# check if our code already exists in the activation script
marker=$(echo "$sh_code" | head -n 2 | tail -n 1)
result=$(grep -F "$marker" "$activation_script")
# add the shell code to the activation script if it hasn't been already
if [ -z "$result" ]; then
echo "$sh_code" >> $activation_script
echo "Configured Kvantum theme support in virtual environment's activate script."
else
echo "Virtual environment's activate script is already configured for Kvantum theme support."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment