|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to enter the virtual environment upgrade |
|
8 parameters. |
|
9 """ |
|
10 |
|
11 import re |
|
12 |
|
13 from PyQt6.QtCore import pyqtSlot, QProcess, QTimer |
|
14 from PyQt6.QtWidgets import QDialog, QDialogButtonBox |
|
15 |
|
16 from EricWidgets.EricPathPicker import EricPathPickerModes |
|
17 |
|
18 from .Ui_VirtualenvUpgradeConfigurationDialog import ( |
|
19 Ui_VirtualenvUpgradeConfigurationDialog |
|
20 ) |
|
21 |
|
22 import Globals |
|
23 import Preferences |
|
24 import Utilities |
|
25 |
|
26 |
|
27 class VirtualenvUpgradeConfigurationDialog( |
|
28 QDialog, Ui_VirtualenvUpgradeConfigurationDialog |
|
29 ): |
|
30 """ |
|
31 Class implementing a dialog to enter the virtual environment upgrade |
|
32 parameters. |
|
33 """ |
|
34 def __init__(self, envName, envPath, parent=None): |
|
35 """ |
|
36 Constructor |
|
37 |
|
38 @param envName name of the environment to be upgraded |
|
39 @type str |
|
40 @param envPath directory of the environment to be upgraded |
|
41 @type str |
|
42 @param parent reference to the parent widget (defaults to None) |
|
43 @type QWidget (optional) |
|
44 """ |
|
45 super().__init__(parent) |
|
46 self.setupUi(self) |
|
47 |
|
48 self.pythonExecPicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) |
|
49 self.pythonExecPicker.setWindowTitle( |
|
50 self.tr("Python Interpreter")) |
|
51 self.pythonExecPicker.setDefaultDirectory( |
|
52 Globals.getPythonExecutable()) |
|
53 |
|
54 self.envNameLabel.setText(envName) |
|
55 self.envDirectoryLabel.setText(envPath) |
|
56 |
|
57 self.__versionRe = re.compile(r""".*?(\d+\.\d+\.\d+).*""") |
|
58 |
|
59 self.upgradePythonCheckBox.toggled.connect(self.__updateOkButton) |
|
60 self.upgradeDepsCheckBox.toggled.connect(self.__updateOkButton) |
|
61 self.pythonExecPicker.textChanged.connect( |
|
62 self.__updateUpgradeDepsCheckBox) |
|
63 |
|
64 self.__updateUpgradeDepsCheckBox() |
|
65 |
|
66 msh = self.minimumSizeHint() |
|
67 self.resize(max(self.width(), msh.width()), msh.height()) |
|
68 |
|
69 def __getPyvenvVersion(self): |
|
70 """ |
|
71 Private method to determine the version of the venv module. |
|
72 |
|
73 @return tuple containing the venv modules version |
|
74 @rtype tuple of (int, int, int) |
|
75 """ |
|
76 calls = [] |
|
77 if self.pythonExecPicker.text(): |
|
78 calls.append((self.pythonExecPicker.text(), |
|
79 ["-m", "venv"])) |
|
80 calls.extend([ |
|
81 (Globals.getPythonExecutable(), ["-m", "venv"]), |
|
82 ("python3", ["-m", "venv"]), |
|
83 ("python", ["-m", "venv"]), |
|
84 ]) |
|
85 |
|
86 proc = QProcess() |
|
87 for prog, args in calls: |
|
88 proc.start(prog, args) |
|
89 |
|
90 if not proc.waitForStarted(5000): |
|
91 # try next entry |
|
92 continue |
|
93 |
|
94 if not proc.waitForFinished(5000): |
|
95 # process hangs, kill it and try next entry |
|
96 QTimer.singleShot(2000, proc.kill) |
|
97 proc.waitForFinished(3000) |
|
98 continue |
|
99 |
|
100 if proc.exitCode() not in [0, 2]: |
|
101 # returned with error code, try next |
|
102 continue |
|
103 |
|
104 proc.start(prog, ["--version"]) |
|
105 proc.waitForFinished(5000) |
|
106 output = str(proc.readAllStandardOutput(), |
|
107 Preferences.getSystem("IOEncoding"), |
|
108 'replace').strip() |
|
109 match = re.match(self.__versionRe, output) |
|
110 if match: |
|
111 return Globals.versionToTuple(match.group(1)) |
|
112 |
|
113 return (0, 0, 0) # dummy version tuple |
|
114 |
|
115 @pyqtSlot() |
|
116 def __updateUpgradeDepsCheckBox(self): |
|
117 """ |
|
118 Private slot to set the enabled state of the button depending |
|
119 on the version of the given Python interpreter. |
|
120 """ |
|
121 pyvenvVersion = self.__getPyvenvVersion() |
|
122 if pyvenvVersion >= (3, 9, 0): |
|
123 self.upgradeDepsCheckBox.setEnabled(True) |
|
124 else: |
|
125 self.upgradeDepsCheckBox.setEnabled(False) |
|
126 self.upgradeDepsCheckBox.setChecked(False) |
|
127 |
|
128 @pyqtSlot() |
|
129 def __updateOkButton(self): |
|
130 """ |
|
131 Private slot to set the enabled state of the OK button. |
|
132 """ |
|
133 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( |
|
134 self.upgradePythonCheckBox.isChecked() or |
|
135 self.upgradeDepsCheckBox.isChecked() |
|
136 ) |
|
137 |
|
138 def getData(self): |
|
139 """ |
|
140 Public method to retrieve the dialog data. |
|
141 |
|
142 @return tuple containing the selected python executable, the list of |
|
143 arguments and a flag indicating to write a log file |
|
144 @rtype tuple of (str, list of str, bool) |
|
145 """ |
|
146 args = ["-m", "venv"] |
|
147 if self.upgradePythonCheckBox.isChecked(): |
|
148 args.append("--upgrade") |
|
149 if self.upgradeDepsCheckBox.isChecked(): |
|
150 args.append("--upgrade-deps") |
|
151 args.append(self.envDirectoryLabel.text()) |
|
152 |
|
153 return ( |
|
154 Utilities.toNativeSeparators(self.pythonExecPicker.text()), |
|
155 args, |
|
156 self.logCheckBox.isChecked(), |
|
157 ) |