Plugins/UiExtensionPlugins/PipInterface/Pip.py

branch
maintenance
changeset 6826
c6dda2cbe081
parent 6764
d14ddbfbbd36
parent 6825
e659bb96cdfa
child 6827
14680839ad7a
equal deleted inserted replaced
6764:d14ddbfbbd36 6826:c6dda2cbe081
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Package implementing the pip GUI logic.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 str = unicode # __IGNORE_EXCEPTION__
13 except NameError:
14 pass
15
16 import os
17 import sys
18
19 from PyQt5.QtCore import pyqtSlot, QObject, QProcess
20 from PyQt5.QtWidgets import QMenu, QInputDialog, QDialog
21
22 from E5Gui import E5MessageBox
23 from E5Gui.E5Action import E5Action
24 from E5Gui.E5Application import e5App
25
26 from .PipDialog import PipDialog
27 from . import DefaultIndexUrlXml
28
29 import Preferences
30 import Globals
31
32
33 class Pip(QObject):
34 """
35 Class implementing the pip GUI logic.
36 """
37 def __init__(self, plugin, parent=None):
38 """
39 Constructor
40
41 @param plugin reference to the plugin object
42 @type PipInterfacePlugin
43 @param parent parent
44 @type QObject
45 """
46 super(Pip, self).__init__(parent)
47
48 self.__plugin = plugin
49 self.__ui = parent
50
51 self.__virtualenvManager = e5App().getObject("VirtualEnvManager")
52 self.__project = e5App().getObject("Project")
53
54 self.__menus = {} # dictionary with references to menus
55
56 self.__plugin.currentEnvironmentChanged.connect(
57 self.__handleTearOffMenu)
58
59 def initActions(self):
60 """
61 Public method to define the actions.
62 """
63 self.actions = []
64
65 self.selectEnvironmentAct = E5Action(
66 self.tr('Virtual Environment for pip'),
67 self.tr('&Virtual Environment for pip'),
68 0, 0,
69 self, 'pip_select_environment')
70 self.selectEnvironmentAct.setStatusTip(self.tr(
71 'Selects the virtual environment to be used for pip'))
72 self.selectEnvironmentAct.setWhatsThis(self.tr(
73 """<b>Virtual Environment for pip</b>"""
74 """<p>This selects the virtual environment to be used for pip."""
75 """</p>"""
76 ))
77 self.selectEnvironmentAct.triggered.connect(self.__selectPipVirtualenv)
78 self.actions.append(self.selectEnvironmentAct)
79
80 ##############################################
81 ## Actions for listing packages
82 ##############################################
83
84 self.listPackagesAct = E5Action(
85 self.tr('List Installed Packages'),
86 self.tr('&List Installed Packages...'),
87 0, 0,
88 self, 'pip_list_packages')
89 self.listPackagesAct.setStatusTip(self.tr(
90 'List all installed packages with versions'))
91 self.listPackagesAct.setWhatsThis(self.tr(
92 """<b>List Installed Packages</b>"""
93 """<p>This lists all the installed packages together"""
94 """ with their versions.</p>"""
95 ))
96 self.listPackagesAct.triggered.connect(self.__listPackages)
97 self.actions.append(self.listPackagesAct)
98
99 self.listUptodatePackagesAct = E5Action(
100 self.tr('List Up-to-date Packages'),
101 self.tr('List Up-to-&date Packages...'),
102 0, 0,
103 self, 'pip_list_uptodate_packages')
104 self.listUptodatePackagesAct.setStatusTip(self.tr(
105 'List all installed, up-to-date packages with versions'))
106 self.listUptodatePackagesAct.setWhatsThis(self.tr(
107 """<b>List Up-to-date Packages</b>"""
108 """<p>This lists all the installed, up-to-date packages together"""
109 """ with their versions.</p>"""
110 ))
111 self.listUptodatePackagesAct.triggered.connect(
112 self.__listUptodatePackages)
113 self.actions.append(self.listUptodatePackagesAct)
114
115 self.listOutdatedPackagesAct = E5Action(
116 self.tr('List Outdated Packages'),
117 self.tr('List &Outdated Packages...'),
118 0, 0,
119 self, 'pip_list_outdated_packages')
120 self.listOutdatedPackagesAct.setStatusTip(self.tr(
121 'List all installed, outdated packages with versions'))
122 self.listOutdatedPackagesAct.setWhatsThis(self.tr(
123 """<b>List Up-to-date Packages</b>"""
124 """<p>This lists all the installed, outdated packages together"""
125 """ with their current and latest versions.</p>"""
126 ))
127 self.listOutdatedPackagesAct.triggered.connect(
128 self.__listOutdatedPackages)
129 self.actions.append(self.listOutdatedPackagesAct)
130
131 ##############################################
132 ## Actions for installing packages
133 ##############################################
134
135 self.installPackagesAct = E5Action(
136 self.tr('Install Packages'),
137 self.tr('&Install Packages'),
138 0, 0,
139 self, 'pip_install_packages')
140 self.installPackagesAct.setStatusTip(self.tr(
141 'Install packages according to user input'))
142 self.installPackagesAct.setWhatsThis(self.tr(
143 """<b>Install Packages</b>"""
144 """<p>This installs packages according to user input.</p>"""
145 ))
146 self.installPackagesAct.triggered.connect(self.__installPackages)
147 self.actions.append(self.installPackagesAct)
148
149 self.installLocalPackageAct = E5Action(
150 self.tr('Install Local Package'),
151 self.tr('Install Local Package'),
152 0, 0,
153 self, 'pip_install_local_package')
154 self.installLocalPackageAct.setStatusTip(self.tr(
155 'Install a package from local storage'))
156 self.installLocalPackageAct.setWhatsThis(self.tr(
157 """<b>Install Local Package</b>"""
158 """<p>This installs a package available on local storage.</p>"""
159 ))
160 self.installLocalPackageAct.triggered.connect(
161 self.__installLocalPackage)
162 self.actions.append(self.installLocalPackageAct)
163
164 self.installRequirementsAct = E5Action(
165 self.tr('Install Requirements'),
166 self.tr('Install Requirements'),
167 0, 0,
168 self, 'pip_install_requirements')
169 self.installRequirementsAct.setStatusTip(self.tr(
170 'Install packages according to a requirements file'))
171 self.installRequirementsAct.setWhatsThis(self.tr(
172 """<b>Install Requirements</b>"""
173 """<p>This installs packages according to a requirements"""
174 """ file.</p>"""
175 ))
176 self.installRequirementsAct.triggered.connect(
177 self.__installRequirements)
178 self.actions.append(self.installRequirementsAct)
179
180 self.installPipAct = E5Action(
181 self.tr('Install Pip'),
182 self.tr('Install Pip'),
183 0, 0,
184 self, 'pip_install_pip')
185 self.installPipAct.setStatusTip(self.tr(
186 'Install the pip package itself'))
187 self.installPipAct.setWhatsThis(self.tr(
188 """<b>Install Pip</b>"""
189 """<p>This installs the pip package itself.</p>"""
190 ))
191 self.installPipAct.triggered.connect(self.__installPip)
192 self.actions.append(self.installPipAct)
193
194 self.repairPipAct = E5Action(
195 self.tr('Repair Pip'),
196 self.tr('Repair Pip'),
197 0, 0,
198 self, 'pip_repair_pip')
199 self.repairPipAct.setStatusTip(self.tr(
200 'Repair the pip package'))
201 self.repairPipAct.setWhatsThis(self.tr(
202 """<b>Repair Pip</b>"""
203 """<p>This repairs the pip package by re-installing it.</p>"""
204 ))
205 self.repairPipAct.triggered.connect(self.__repairPip)
206 self.actions.append(self.repairPipAct)
207
208 self.upgradePipAct = E5Action(
209 self.tr('Upgrade Pip'),
210 self.tr('Upgrade &Pip'),
211 0, 0,
212 self, 'pip_upgrade_pip')
213 self.upgradePipAct.setStatusTip(self.tr(
214 'Upgrade the pip package itself'))
215 self.upgradePipAct.setWhatsThis(self.tr(
216 """<b>Upgrade Pip</b>"""
217 """<p>This upgrades the pip package itself.</p>"""
218 ))
219 self.upgradePipAct.triggered.connect(self.upgradePip)
220 self.actions.append(self.upgradePipAct)
221
222 self.upgradePackagesAct = E5Action(
223 self.tr('Upgrade Packages'),
224 self.tr('&Upgrade Packages'),
225 0, 0,
226 self, 'pip_upgrade_packages')
227 self.upgradePackagesAct.setStatusTip(self.tr(
228 'Upgrade packages according to user input'))
229 self.upgradePackagesAct.setWhatsThis(self.tr(
230 """<b>Upgrade Packages</b>"""
231 """<p>This upgrades packages according to user input.</p>"""
232 ))
233 self.upgradePackagesAct.triggered.connect(self.__upgradePackages)
234 self.actions.append(self.upgradePackagesAct)
235
236 ##############################################
237 ## Actions for uninstalling packages
238 ##############################################
239
240 self.uninstallPackagesAct = E5Action(
241 self.tr('Uninstall Packages'),
242 self.tr('Uninstall Packages'),
243 0, 0,
244 self, 'pip_uninstall_packages')
245 self.uninstallPackagesAct.setStatusTip(self.tr(
246 'Uninstall packages according to user input'))
247 self.uninstallPackagesAct.setWhatsThis(self.tr(
248 """<b>Uninstall Packages</b>"""
249 """<p>This uninstalls packages according to user input.</p>"""
250 ))
251 self.uninstallPackagesAct.triggered.connect(self.__uninstallPackages)
252 self.actions.append(self.uninstallPackagesAct)
253
254 self.uninstallRequirementsAct = E5Action(
255 self.tr('Uninstall Requirements'),
256 self.tr('Uninstall Requirements'),
257 0, 0,
258 self, 'pip_uninstall_requirements')
259 self.uninstallRequirementsAct.setStatusTip(self.tr(
260 'Uninstall packages according to a requirements file'))
261 self.uninstallRequirementsAct.setWhatsThis(self.tr(
262 """<b>Uninstall Requirements</b>"""
263 """<p>This uninstalls packages according to a requirements"""
264 """ file.</p>"""
265 ))
266 self.uninstallRequirementsAct.triggered.connect(
267 self.__uninstallRequirements)
268 self.actions.append(self.uninstallRequirementsAct)
269
270 ##############################################
271 ## Actions for generating requirements files
272 ##############################################
273
274 self.generateRequirementsAct = E5Action(
275 self.tr('Generate Requirements'),
276 self.tr('&Generate Requirements...'),
277 0, 0,
278 self, 'pip_generate_requirements')
279 self.generateRequirementsAct.setStatusTip(self.tr(
280 'Generate the contents of a requirements file'))
281 self.generateRequirementsAct.setWhatsThis(self.tr(
282 """<b>Generate Requirements</b>"""
283 """<p>This generates the contents of a requirements file.</p>"""
284 ))
285 self.generateRequirementsAct.triggered.connect(
286 self.__generateRequirements)
287 self.actions.append(self.generateRequirementsAct)
288
289 ##############################################
290 ## Actions for generating requirements files
291 ##############################################
292
293 self.searchPyPIAct = E5Action(
294 self.tr('Search PyPI'),
295 self.tr('&Search PyPI...'),
296 0, 0,
297 self, 'pip_search_pypi')
298 self.searchPyPIAct.setStatusTip(self.tr(
299 'Open a dialog to search the Python Package Index'))
300 self.searchPyPIAct.setWhatsThis(self.tr(
301 """<b>Search PyPI</b>"""
302 """<p>This opens a dialog to search the Python Package"""
303 """ Index.</p>"""
304 ))
305 self.searchPyPIAct.triggered.connect(self.__searchPyPI)
306 self.actions.append(self.searchPyPIAct)
307
308 ##############################################
309 ## Actions for editing configuration files
310 ##############################################
311
312 self.editUserConfigAct = E5Action(
313 self.tr('Edit User Configuration'),
314 self.tr('Edit User Configuration...'),
315 0, 0,
316 self, 'pip_edit_user_config')
317 self.editUserConfigAct.setStatusTip(self.tr(
318 'Open the per user configuration file in an editor'))
319 self.editUserConfigAct.setWhatsThis(self.tr(
320 """<b>Edit User Configuration</b>"""
321 """<p>This opens the per user configuration file in an editor."""
322 """</p>"""
323 ))
324 self.editUserConfigAct.triggered.connect(self.__editUserConfiguration)
325 self.actions.append(self.editUserConfigAct)
326
327 self.editVirtualenvConfigAct = E5Action(
328 self.tr('Edit Current Virtualenv Configuration'),
329 self.tr('Edit Current Virtualenv Configuration...'),
330 0, 0,
331 self, 'pip_edit_virtualenv_config')
332 self.editVirtualenvConfigAct.setStatusTip(self.tr(
333 'Open the current virtualenv configuration file in an editor'))
334 self.editVirtualenvConfigAct.setWhatsThis(self.tr(
335 """<b>Edit Current Virtualenv Configuration</b>"""
336 """<p>This opens the current virtualenv configuration file in"""
337 """ an editor. </p>"""
338 ))
339 self.editVirtualenvConfigAct.triggered.connect(
340 self.__editVirtualenvConfiguration)
341 self.actions.append(self.editVirtualenvConfigAct)
342
343 self.pipConfigAct = E5Action(
344 self.tr('Configure'),
345 self.tr('Configure...'),
346 0, 0, self, 'pip_configure')
347 self.pipConfigAct.setStatusTip(self.tr(
348 'Show the configuration dialog with the Python Package Management'
349 ' page selected'
350 ))
351 self.pipConfigAct.setWhatsThis(self.tr(
352 """<b>Configure</b>"""
353 """<p>Show the configuration dialog with the Python Package"""
354 """ Management page selected.</p>"""
355 ))
356 self.pipConfigAct.triggered.connect(self.__pipConfigure)
357 self.actions.append(self.pipConfigAct)
358
359 def initMenu(self):
360 """
361 Public slot to initialize the menu.
362
363 @return the menu generated
364 @rtype QMenu
365 """
366 self.__menus = {} # clear menus references
367
368 menu = QMenu(self.tr('P&ython Package Management'), self.__ui)
369 menu.setTearOffEnabled(True)
370
371 menu.addAction(self.selectEnvironmentAct)
372 menu.addSeparator()
373 menu.addAction(self.listPackagesAct)
374 menu.addAction(self.listUptodatePackagesAct)
375 menu.addAction(self.listOutdatedPackagesAct)
376 menu.addSeparator()
377 menu.addAction(self.installPipAct)
378 menu.addSeparator()
379 menu.addAction(self.installPackagesAct)
380 menu.addAction(self.installLocalPackageAct)
381 menu.addAction(self.installRequirementsAct)
382 menu.addSeparator()
383 menu.addAction(self.upgradePipAct)
384 menu.addAction(self.upgradePackagesAct)
385 menu.addSeparator()
386 menu.addAction(self.uninstallPackagesAct)
387 menu.addAction(self.uninstallRequirementsAct)
388 menu.addSeparator()
389 menu.addAction(self.generateRequirementsAct)
390 menu.addSeparator()
391 menu.addAction(self.searchPyPIAct)
392 menu.addSeparator()
393 menu.addAction(self.repairPipAct)
394 menu.addSeparator()
395 menu.addAction(self.editUserConfigAct)
396 menu.addAction(self.editVirtualenvConfigAct)
397 menu.addSeparator()
398 menu.addAction(self.pipConfigAct)
399
400 self.__menus["main"] = menu
401
402 menu.aboutToShow.connect(self.__aboutToShowMenu)
403
404 return menu
405
406 def __aboutToShowMenu(self):
407 """
408 Private slot to set the action enabled status.
409 """
410 enable = bool(self.__plugin.getPreferences("CurrentEnvironment"))
411 for act in self.actions:
412 if act not in [self.selectEnvironmentAct,
413 self.installPipAct,
414 self.editUserConfigAct,
415 self.editVirtualenvConfigAct,
416 self.pipConfigAct]:
417 act.setEnabled(enable)
418
419 def getMenu(self, name):
420 """
421 Public method to get a reference to the requested menu.
422
423 @param name name of the menu
424 @type str
425 @return reference to the menu or None, if no
426 menu with the given name exists
427 @rtype QMenu or None
428 """
429 if name in self.__menus:
430 return self.__menus[name]
431 else:
432 return None
433
434 def getMenuNames(self):
435 """
436 Public method to get the names of all menus.
437
438 @return menu names
439 @rtype list of str
440 """
441 return list(self.__menus.keys())
442
443 def __handleTearOffMenu(self, venvName):
444 """
445 Private slot to handle a change of the selected virtual environment.
446
447 @param venvName logical name of the virtual environment
448 @type str
449 """
450 if self.__menus["main"].isTearOffMenuVisible():
451 # determine, if torn off menu needs to be refreshed
452 enabled = self.listPackagesAct.isEnabled()
453 if ((bool(venvName) and not enabled) or
454 (not bool(venvName) and enabled)):
455 self.__menus["main"].hideTearOffMenu()
456
457 ##########################################################################
458 ## Methods below implement some utility functions
459 ##########################################################################
460
461 def runProcess(self, args, interpreter):
462 """
463 Public method to execute the current pip with the given arguments.
464
465 The selected pip executable is called with the given arguments and
466 waited for its end.
467
468 @param args list of command line arguments
469 @type list of str
470 @param interpreter path of the Python interpreter to be used
471 @type str
472 @return tuple containing a flag indicating success and the output
473 of the process
474 @rtype tuple of (bool, str)
475 """
476 ioEncoding = Preferences.getSystem("IOEncoding")
477
478 process = QProcess()
479 process.start(interpreter, args)
480 procStarted = process.waitForStarted()
481 if procStarted:
482 finished = process.waitForFinished(30000)
483 if finished:
484 if process.exitCode() == 0:
485 output = str(process.readAllStandardOutput(), ioEncoding,
486 'replace')
487 return True, output
488 else:
489 return (False,
490 self.tr("python exited with an error ({0}).")
491 .format(process.exitCode()))
492 else:
493 process.terminate()
494 process.waitForFinished(2000)
495 process.kill()
496 process.waitForFinished(3000)
497 return False, self.tr("python did not finish within"
498 " 30 seconds.")
499
500 return False, self.tr("python could not be started.")
501
502 def __getUserConfig(self):
503 """
504 Private method to get the name of the user configuration file.
505
506 @return path of the user configuration file
507 @rtype str
508 """
509 # Unix: ~/.config/pip/pip.conf
510 # OS X: ~/Library/Application Support/pip/pip.conf
511 # Windows: %APPDATA%\pip\pip.ini
512 # Environment: $PIP_CONFIG_FILE
513
514 try:
515 return os.environ["PIP_CONFIG_FILE"]
516 except KeyError:
517 pass
518
519 if Globals.isWindowsPlatform():
520 config = os.path.join(os.environ["APPDATA"], "pip", "pip.ini")
521 elif Globals.isMacPlatform():
522 config = os.path.expanduser(
523 "~/Library/Application Support/pip/pip.conf")
524 else:
525 config = os.path.expanduser("~/.config/pip/pip.conf")
526
527 return config
528
529 def __getVirtualenvConfig(self):
530 """
531 Private method to get the name of the virtualenv configuration file.
532
533 @return path of the virtualenv configuration file
534 @rtype str
535 """
536 # Unix, OS X: $VIRTUAL_ENV/pip.conf
537 # Windows: %VIRTUAL_ENV%\pip.ini
538
539 if Globals.isWindowsPlatform():
540 pip = "pip.ini"
541 else:
542 pip = "pip.conf"
543 try:
544 venvDirectory = os.environ["VIRTUAL_ENV"]
545 except KeyError:
546 venvName = self.__plugin.getPreferences("CurrentEnvironment")
547 if not venvName:
548 self.__selectPipVirtualenv()
549 venvName = self.__plugin.getPreferences("CurrentEnvironment")
550 if self.__virtualenvManager.isGlobalEnvironment(venvName):
551 venvDirectory = self.__getUserConfig()
552 else:
553 venvDirectory = \
554 self.__virtualenvManager.getVirtualenvDirectory(venvName)
555
556 return os.path.join(venvDirectory, pip)
557
558 def getDefaultEnvironmentString(self):
559 """
560 Public method to get the string for the default environment.
561
562 @return string for the default environment
563 @rtype str
564 """
565 return self.tr("<standard>")
566
567 def getProjectEnvironmentString(self):
568 """
569 Public method to get the string for the project environment.
570
571 @return string for the project environment
572 @rtype str
573 """
574 if self.__project.isOpen():
575 return self.tr("<project>")
576 else:
577 return ""
578
579 def getVirtualenvInterpreter(self, venvName):
580 """
581 Public method to get the interpreter for a virtual environment.
582
583 @param venvName logical name for the virtual environment
584 @type str
585 @return interpreter path
586 @rtype str
587 """
588 if venvName == self.getDefaultEnvironmentString():
589 venvName = self.__plugin.getPreferences("CurrentEnvironment")
590 elif venvName == self.getProjectEnvironmentString():
591 venvName = self.__project.getDebugProperty("VIRTUALENV")
592 if not venvName:
593 # fall back to standard if not defined
594 venvName = self.__plugin.getPreferences("CurrentEnvironment")
595
596 interpreter = self.__virtualenvManager.getVirtualenvInterpreter(
597 venvName)
598 if not interpreter:
599 E5MessageBox.critical(
600 None,
601 self.tr("Interpreter for Virtual Environment"),
602 self.tr("""No interpreter configured for the selected"""
603 """ virtual environment."""))
604
605 return interpreter
606
607 def getVirtualenvNames(self):
608 """
609 Public method to get a sorted list of virtual environment names.
610
611 @return sorted list of virtual environment names
612 @rtype list of str
613 """
614 return sorted(self.__virtualenvManager.getVirtualenvNames())
615
616 ##########################################################################
617 ## Methods below implement the individual menu entries
618 ##########################################################################
619
620 def __selectPipVirtualenv(self):
621 """
622 Private method to select the virtual environment to be used.
623 """
624 environments = self.getVirtualenvNames()
625 if environments:
626 currentEnvironment = self.__plugin.getPreferences(
627 "CurrentEnvironment")
628 try:
629 index = environments.index(currentEnvironment)
630 except ValueError:
631 index = 0
632 environment, ok = QInputDialog.getItem(
633 None,
634 self.tr("Virtual Environment for pip"),
635 self.tr("Select the virtual environment to be used:"),
636 environments, index, False)
637
638 if ok and environment:
639 self.__plugin.setPreferences("CurrentEnvironment",
640 environment)
641 else:
642 E5MessageBox.warning(
643 None,
644 self.tr("Virtual Environment for pip"),
645 self.tr("""No virtual environments have been configured yet."""
646 """ Please use the Virtualenv Manager to do that."""))
647
648 def __listPackages(self):
649 """
650 Private slot to list all installed packages.
651 """
652 from .PipListDialog import PipListDialog
653 self.__listDialog = PipListDialog(
654 self, "list", self.__plugin.getPreferences("PipSearchIndex"),
655 self.tr("Installed Packages"))
656 self.__listDialog.show()
657 self.__listDialog.start()
658
659 def __listUptodatePackages(self):
660 """
661 Private slot to list all installed, up-to-date packages.
662 """
663 from .PipListDialog import PipListDialog
664 self.__listUptodateDialog = PipListDialog(
665 self, "uptodate", self.__plugin.getPreferences("PipSearchIndex"),
666 self.tr("Up-to-date Packages"))
667 self.__listUptodateDialog.show()
668 self.__listUptodateDialog.start()
669
670 def __listOutdatedPackages(self):
671 """
672 Private slot to list all installed, up-to-date packages.
673 """
674 from .PipListDialog import PipListDialog
675 self.__listOutdatedDialog = PipListDialog(
676 self, "outdated", self.__plugin.getPreferences("PipSearchIndex"),
677 self.tr("Outdated Packages"))
678 self.__listOutdatedDialog.show()
679 self.__listOutdatedDialog.start()
680
681 def __editUserConfiguration(self):
682 """
683 Private slot to edit the user configuration.
684 """
685 self.__editConfiguration()
686
687 def __editVirtualenvConfiguration(self):
688 """
689 Private slot to edit the current virtualenv configuration.
690 """
691 self.__editConfiguration(virtualenv=True)
692
693 def __editConfiguration(self, virtualenv=False):
694 """
695 Private method to edit a configuration.
696
697 @param virtualenv flag indicating to edit the current virtualenv
698 configuration file
699 @type bool
700 """
701 from QScintilla.MiniEditor import MiniEditor
702 if virtualenv:
703 cfgFile = self.__getVirtualenvConfig()
704 else:
705 cfgFile = self.__getUserConfig()
706 cfgDir = os.path.dirname(cfgFile)
707 if not cfgDir:
708 E5MessageBox.critical(
709 None,
710 self.tr("Edit Configuration"),
711 self.tr("""No valid configuration path determined."""
712 """ Is a virtual environment selected? Aborting"""))
713 return
714
715 try:
716 if not os.path.isdir(cfgDir):
717 os.makedirs(cfgDir)
718 except OSError:
719 E5MessageBox.critical(
720 None,
721 self.tr("Edit Configuration"),
722 self.tr("""No valid configuration path determined."""
723 """ Is a virtual environment selected? Aborting"""))
724 return
725
726 if not os.path.exists(cfgFile):
727 try:
728 f = open(cfgFile, "w")
729 f.write("[global]\n")
730 f.close()
731 except (IOError, OSError):
732 # ignore these
733 pass
734
735 # check, if the destination is writeable
736 if not os.access(cfgFile, os.W_OK):
737 E5MessageBox.critical(
738 None,
739 self.tr("Edit Configuration"),
740 self.tr("""No valid configuartion path determined."""
741 """ Is a virtual environment selected? Aborting"""))
742 return
743
744 self.__editor = MiniEditor(cfgFile, "Properties")
745 self.__editor.show()
746
747 def __installPip(self, userSite=False):
748 """
749 Private slot to install pip.
750
751 @param userSite flag indicating an install to the user install
752 directory
753 @type bool
754 """
755 from .PipSelectionDialog import PipSelectionDialog
756 dlg = PipSelectionDialog(self)
757 if dlg.exec_() != QDialog.Accepted:
758 return
759
760 venvName, userSite = dlg.getData()
761 interpreter = self.getVirtualenvInterpreter(venvName)
762 if not interpreter:
763 return
764
765 dia = PipDialog(self.tr('Install PIP'))
766 if userSite:
767 commands = [(interpreter, ["-m", "ensurepip", "--user"])]
768 else:
769 commands = [(interpreter, ["-m", "ensurepip"])]
770 if self.__plugin.getPreferences("PipSearchIndex"):
771 indexUrl = \
772 self.__plugin.getPreferences("PipSearchIndex") + "/simple"
773 args = ["-m", "pip", "install", "--index-url", indexUrl,
774 "--upgrade"]
775 else:
776 args = ["-m", "pip", "install", "--upgrade"]
777 if userSite:
778 args.append("--user")
779 args.append("pip")
780 commands.append((interpreter, args[:]))
781
782 res = dia.startProcesses(commands)
783 if res:
784 dia.exec_()
785
786 @pyqtSlot()
787 def upgradePip(self, venvName="", userSite=False):
788 """
789 Public method to upgrade pip itself.
790
791 @param venvName name of the virtual environment to be used
792 @type str
793 @param userSite flag indicating an install to the user install
794 directory
795 @type bool
796 @return flag indicating a successful execution
797 @rtype bool
798 """
799 # Upgrading pip needs to be treated specially because
800 # it must be done using the python executable
801
802 if not venvName:
803 from .PipSelectionDialog import PipSelectionDialog
804 dlg = PipSelectionDialog(self)
805 if dlg.exec_() != QDialog.Accepted:
806 return
807
808 venvName, userSite = dlg.getData()
809
810 interpreter = self.getVirtualenvInterpreter(venvName)
811 if not interpreter:
812 return
813
814 if self.__plugin.getPreferences("PipSearchIndex"):
815 indexUrl = \
816 self.__plugin.getPreferences("PipSearchIndex") + "/simple"
817 args = ["-m", "pip", "install", "--index-url", indexUrl,
818 "--upgrade"]
819 else:
820 args = ["-m", "pip", "install", "--upgrade"]
821 if userSite:
822 args.append("--user")
823 args.append("pip")
824
825 dia = PipDialog(self.tr('Upgrade PIP'))
826 res = dia.startProcess(interpreter, args)
827 if res:
828 dia.exec_()
829 return res
830
831 @pyqtSlot()
832 def __repairPip(self):
833 """
834 Private method to repair the pip installation.
835
836 @return flag indicating a successful execution
837 @rtype bool
838 """
839 from .PipSelectionDialog import PipSelectionDialog
840 dlg = PipSelectionDialog(self)
841 if dlg.exec_() != QDialog.Accepted:
842 return False
843
844 venvName, userSite = dlg.getData()
845 interpreter = self.getVirtualenvInterpreter(venvName)
846 if not interpreter:
847 return
848
849 # python -m pip install --ignore-installed pip
850 if self.__plugin.getPreferences("PipSearchIndex"):
851 indexUrl = \
852 self.__plugin.getPreferences("PipSearchIndex") + "/simple"
853 args = ["-m", "pip", "install", "--index-url", indexUrl,
854 "--ignore-installed"]
855 else:
856 args = ["-m", "pip", "install", "--ignore-installed"]
857 if userSite:
858 args.append("--user")
859 args.append("pip")
860
861 dia = PipDialog(self.tr('Repair PIP'))
862 res = dia.startProcess(interpreter, args)
863 if res:
864 dia.exec_()
865
866 def __checkUpgradePyQt(self, packages):
867 """
868 Private method to check, if an upgrade of PyQt packages is attempted.
869
870 @param packages list of packages to upgrade
871 @type list of str
872 @return flag indicating to abort the upgrade attempt
873 @rtype bool
874 """
875 pyqtPackages = [p for p in packages
876 if p.lower() in ["pyqt5", "qscintilla", "sip"]]
877
878 if bool(pyqtPackages):
879 abort = not E5MessageBox.yesNo(
880 None,
881 self.tr("Upgrade Packages"),
882 self.tr(
883 """You are trying to upgrade PyQt packages. This will"""
884 """ not work for the current instance of Python ({0})."""
885 """ Do you want to continue?""").format(sys.executable),
886 icon=E5MessageBox.Critical)
887 else:
888 abort = False
889
890 return abort
891
892 def upgradePackages(self, packages, venvName="", userSite=False):
893 """
894 Public method to upgrade the given list of packages.
895
896 @param packages list of packages to upgrade
897 @type list of str
898 @param venvName name of the virtual environment to be used
899 @type str
900 @param userSite flag indicating an install to the user install
901 directory
902 @type bool
903 @return flag indicating a successful execution
904 @rtype bool
905 """
906 if self.__checkUpgradePyQt(packages):
907 return False
908
909 if not venvName:
910 venvName = self.__plugin.getPreferences("CurrentEnvironment")
911 interpreter = self.getVirtualenvInterpreter(venvName)
912 if not interpreter:
913 return
914
915 if self.__plugin.getPreferences("PipSearchIndex"):
916 indexUrl = \
917 self.__plugin.getPreferences("PipSearchIndex") + "/simple"
918 args = ["-m", "pip", "install", "--index-url", indexUrl,
919 "--upgrade"]
920 else:
921 args = ["-m", "pip", "install", "--upgrade"]
922 if userSite:
923 args.append("--user")
924 args += packages
925 dia = PipDialog(self.tr('Upgrade Packages'))
926 res = dia.startProcess(interpreter, args)
927 if res:
928 dia.exec_()
929 return res
930
931 def __upgradePackages(self):
932 """
933 Private slot to upgrade packages to be given by the user.
934 """
935 from .PipPackagesInputDialog import PipPackagesInputDialog
936 dlg = PipPackagesInputDialog(self, self.tr("Upgrade Packages"))
937 if dlg.exec_() == QDialog.Accepted:
938 venvName, packages, user = dlg.getData()
939 if packages:
940 self.upgradePackages(packages, venvName=venvName,
941 userSite=user)
942
943 def installPackages(self, packages, venvName="", userSite=False):
944 """
945 Public method to install the given list of packages.
946
947 @param packages list of packages to install
948 @type list of str
949 @param venvName name of the virtual environment to be used
950 @type str
951 @param userSite flag indicating an install to the user install
952 directory
953 @type bool
954 """
955 if not venvName:
956 venvName = self.__plugin.getPreferences("CurrentEnvironment")
957 interpreter = self.getVirtualenvInterpreter(venvName)
958 if not interpreter:
959 return
960
961 if self.__plugin.getPreferences("PipSearchIndex"):
962 indexUrl = \
963 self.__plugin.getPreferences("PipSearchIndex") + "/simple"
964 args = ["-m", "pip", "install", "--index-url", indexUrl]
965 else:
966 args = ["-m", "pip", "install"]
967 if userSite:
968 args.append("--user")
969 args += packages
970 dia = PipDialog(self.tr('Install Packages'))
971 res = dia.startProcess(interpreter, args)
972 if res:
973 dia.exec_()
974
975 def __installPackages(self):
976 """
977 Private slot to install packages to be given by the user.
978 """
979 from .PipPackagesInputDialog import PipPackagesInputDialog
980 dlg = PipPackagesInputDialog(
981 self, self.tr("Install Packages"))
982 if dlg.exec_() == QDialog.Accepted:
983 venvName, packages, user = dlg.getData()
984 if packages:
985 self.installPackages(packages, venvName=venvName,
986 userSite=user)
987
988 def __installLocalPackage(self):
989 """
990 Private slot to install a package available on local storage.
991 """
992 from .PipFileSelectionDialog import PipFileSelectionDialog
993 dlg = PipFileSelectionDialog(self, "package")
994 if dlg.exec_() == QDialog.Accepted:
995 venvName, package, user = dlg.getData()
996 if package and os.path.exists(package):
997 self.installPackages([package], venvName=venvName,
998 userSite=user)
999
1000 def __installRequirements(self):
1001 """
1002 Private slot to install packages as given in a requirements file.
1003 """
1004 from .PipFileSelectionDialog import PipFileSelectionDialog
1005 dlg = PipFileSelectionDialog(self, "requirements")
1006 if dlg.exec_() == QDialog.Accepted:
1007 venvName, requirements, user = dlg.getData()
1008 if requirements and os.path.exists(requirements):
1009 interpreter = self.getVirtualenvInterpreter(venvName)
1010 if not interpreter:
1011 return
1012 if self.__plugin.getPreferences("PipSearchIndex"):
1013 indexUrl = \
1014 self.__plugin.getPreferences("PipSearchIndex") + \
1015 "/simple"
1016 args = ["-m", "pip", "install", "--index-url", indexUrl]
1017 else:
1018 args = ["-m", "pip", "install"]
1019 if user:
1020 args.append("--user")
1021 args += ["--requirement", requirements]
1022 dia = PipDialog(self.tr('Install Packages from Requirements'))
1023 res = dia.startProcess(interpreter, args)
1024 if res:
1025 dia.exec_()
1026
1027 def uninstallPackages(self, packages, venvName=""):
1028 """
1029 Public method to uninstall the given list of packages.
1030
1031 @param packages list of packages to uninstall
1032 @type list of str
1033 @param venvName name of the virtual environment to be used
1034 @type str
1035 @return flag indicating a successful execution
1036 @rtype bool
1037 """
1038 res = False
1039 if packages:
1040 from UI.DeleteFilesConfirmationDialog import \
1041 DeleteFilesConfirmationDialog
1042 dlg = DeleteFilesConfirmationDialog(
1043 self.parent(),
1044 self.tr("Uninstall Packages"),
1045 self.tr(
1046 "Do you really want to uninstall these packages?"),
1047 packages)
1048 if dlg.exec_() == QDialog.Accepted:
1049 if not venvName:
1050 venvName = self.__plugin.getPreferences(
1051 "CurrentEnvironment")
1052 interpreter = self.getVirtualenvInterpreter(venvName)
1053 if not interpreter:
1054 return
1055 args = ["-m", "pip", "uninstall", "--yes"] + packages
1056 dia = PipDialog(self.tr('Uninstall Packages'))
1057 res = dia.startProcess(interpreter, args)
1058 if res:
1059 dia.exec_()
1060 return res
1061
1062 def __uninstallPackages(self):
1063 """
1064 Private slot to uninstall packages to be given by the user.
1065 """
1066 from .PipPackagesInputDialog import PipPackagesInputDialog
1067 dlg = PipPackagesInputDialog(
1068 self, self.tr("Uninstall Packages"), install=False)
1069 if dlg.exec_() == QDialog.Accepted:
1070 venvName, packages, _user = dlg.getData()
1071 if packages:
1072 self.uninstallPackages(packages, venvName=venvName)
1073
1074 def __uninstallRequirements(self):
1075 """
1076 Private slot to uninstall packages as given in a requirements file.
1077 """
1078 from .PipFileSelectionDialog import PipFileSelectionDialog
1079 dlg = PipFileSelectionDialog(self, "requirements",
1080 install=False)
1081 if dlg.exec_() == QDialog.Accepted:
1082 venvName, requirements, _user = dlg.getData()
1083 if requirements and os.path.exists(requirements):
1084 try:
1085 f = open(requirements, "r")
1086 reqs = f.read().splitlines()
1087 f.close()
1088 except (OSError, IOError):
1089 return
1090
1091 from UI.DeleteFilesConfirmationDialog import \
1092 DeleteFilesConfirmationDialog
1093 dlg = DeleteFilesConfirmationDialog(
1094 self.parent(),
1095 self.tr("Uninstall Packages"),
1096 self.tr(
1097 "Do you really want to uninstall these packages?"),
1098 reqs)
1099 if dlg.exec_() == QDialog.Accepted:
1100 if not venvName:
1101 venvName = self.__plugin.getPreferences(
1102 "CurrentEnvironment")
1103 interpreter = self.getVirtualenvInterpreter(venvName)
1104 if not interpreter:
1105 return
1106 args = ["-m", "pip", "uninstall", "--requirement",
1107 requirements]
1108 dia = PipDialog(
1109 self.tr('Uninstall Packages from Requirements'))
1110 res = dia.startProcess(interpreter, args)
1111 if res:
1112 dia.exec_()
1113
1114 def __generateRequirements(self):
1115 """
1116 Private slot to generate the contents for a requirements file.
1117 """
1118 from .PipFreezeDialog import PipFreezeDialog
1119 self.__freezeDialog = PipFreezeDialog(self)
1120 self.__freezeDialog.show()
1121 self.__freezeDialog.start()
1122
1123 def __searchPyPI(self):
1124 """
1125 Private slot to search the Python Package Index.
1126 """
1127 from .PipSearchDialog import PipSearchDialog
1128
1129 if self.__plugin.getPreferences("PipSearchIndex"):
1130 indexUrl = self.__plugin.getPreferences("PipSearchIndex") + "/pypi"
1131 else:
1132 indexUrl = DefaultIndexUrlXml
1133
1134 self.__searchDialog = PipSearchDialog(self, indexUrl)
1135 self.__searchDialog.show()
1136
1137 def __pipConfigure(self):
1138 """
1139 Private slot to open the configuration page.
1140 """
1141 e5App().getObject("UserInterface").showPreferences("pipPage")

eric ide

mercurial