Skip to content

Commit

Permalink
Add ProgressDialog to PySide upgrade action
Browse files Browse the repository at this point in the history
  • Loading branch information
mrvisscher committed Nov 22, 2024
1 parent 1ab019c commit 730e4e0
Showing 1 changed file with 78 additions and 15 deletions.
93 changes: 78 additions & 15 deletions activity_browser/actions/pyside_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,109 @@
import os
import sys
import subprocess
import time

from activity_browser import application
from activity_browser.actions.base import ABAction, exception_dialogs
from activity_browser.ui.icons import qicons
from activity_browser.ui import threading, icons

from qtpy import QtWidgets
from qtpy.QtCore import Signal, SignalInstance


class PysideUpgrade(ABAction):
"""
ABAction to install all the default data: biosphere, IC's etcetera.
ABAction to install PySide6 through PyPI/pip. Installs PySide6, sets the environment variable for QtPy to use
PySide6 and then restarts the Activity Browser through a subprocess.
"""

icon = qicons.forward
icon = icons.qicons.forward
text = "Upgrade installation to PySide6"

@classmethod
@exception_dialogs
def run(cls):

# slot definition to update the progress dialog with thread updates
def update_dialog_slot(progress: int, label: str):
dialog.setValue(progress)
dialog.setLabelText(label)

assert not qtpy.PYSIDE6, "Already running PySide6"
assert cls.in_conda(), "Not inside a Conda environment"

cls.pypi_install()
cls.set_conda_env_var()
cls.restart()
# setup a progress dialog to show the user we're doing something
dialog = QtWidgets.QProgressDialog(application.main_window)
dialog.setWindowTitle("Upgrading GUI back-end")
dialog.setMaximum(0)
dialog.setCancelButton(None)

# messages can get quite long, so enable word-wrapping
lbl = dialog.findChild(QtWidgets.QLabel)
lbl.setWordWrap(True)

# initialize thread and connect signals
thread = PySideUpgradeThread(application)
thread.status.connect(update_dialog_slot)
thread.exit.connect(sys.exit)

thread.start()
dialog.exec_()

@staticmethod
def in_conda() -> bool:
"""Returns true when the current shell is in a Conda environment."""
return bool(os.environ.get("CONDA_DEFAULT_ENV", False))

@staticmethod
def pypi_install():
process = subprocess.run(["pip", "install", "pyside6"])

class PySideUpgradeThread(threading.ABThread):
exit: SignalInstance = Signal()

def run_safely(self):
self.pip_installation()
self.set_conda_env_var()
self.restart()

def pip_installation(self):
"""
Install PySide6 from PyPI using a subprocess.Popen call
"""
self.status.emit(0, "Installing PySide6 through pip")

# open subprocess that installs PySide6
process = subprocess.Popen(["pip", "install", "pyside6"], stdout=subprocess.PIPE)

while process.poll() is None: # block until the subprocess is finished
# format stdout
line = process.stdout.readline().decode().strip()
if not line:
continue

# redirect stdout to both console and progress dialog
print(line)
self.status.emit(0, line)

assert process.returncode == 0, "Failed to install PySide6"

@staticmethod
def set_conda_env_var():
def set_conda_env_var(self):
"""
Set the QT_API QtPy environment variable persistently for this conda environment
"""
self.status.emit(0, "Setting QT_API environment variable")

subprocess.run(["conda", "env", "config", "vars", "set", "QT_API=pyside6"])
os.environ["QT_API"] = "pyside6"
os.environ["QT_API"] = "pyside6" # also set for the env directly for the restart

@staticmethod
def restart():
def restart(self):
"""
Restarts the Activity Browser through a subprocess. Sleeps 5 seconds to allow the user to register
the restart.
"""
self.status.emit(0, "Restarting the Activity Browser")
subprocess.Popen(["python", "-c", "import activity_browser; activity_browser.run_activity_browser()"])
sys.exit()
time.sleep(5)

# signal restart through the exit signal as sys.exit needs to be called in the main thread.
self.exit.emit()


0 comments on commit 730e4e0

Please sign in to comment.