PipInterface/PipPackagesWidget.py

branch
pypi
changeset 6795
6e2ed2aac325
parent 6793
cca6a35f3ad2
child 6798
3985c1a67fa2
equal deleted inserted replaced
6793:cca6a35f3ad2 6795:6e2ed2aac325
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 import textwrap 12 import textwrap
13 import os
13 14
14 from PyQt5.QtCore import pyqtSlot, Qt, QEventLoop, QRegExp 15 from PyQt5.QtCore import pyqtSlot, Qt, QEventLoop, QRegExp
15 from PyQt5.QtGui import QCursor 16 from PyQt5.QtGui import QCursor
16 from PyQt5.QtWidgets import QWidget, QToolButton, QApplication, QHeaderView, \ 17 from PyQt5.QtWidgets import QWidget, QToolButton, QApplication, QHeaderView, \
17 QTreeWidgetItem 18 QTreeWidgetItem, QInputDialog, QMenu, QDialog
18 19
19 from E5Gui.E5Application import e5App 20 from E5Gui.E5Application import e5App
20 from E5Gui import E5MessageBox 21 from E5Gui import E5MessageBox
21 22
22 from E5Network.E5XmlRpcClient import E5XmlRpcClient 23 from E5Network.E5XmlRpcClient import E5XmlRpcClient
107 self.__populateEnvironments() 108 self.__populateEnvironments()
108 self.__updateActionButtons() 109 self.__updateActionButtons()
109 110
110 self.statusLabel.hide() 111 self.statusLabel.hide()
111 self.searchWidget.hide() 112 self.searchWidget.hide()
113
114 self.__detailsData = {}
115 self.__query = []
116
117 self.__packageDetailsDialog = None
112 118
113 def __populateEnvironments(self): 119 def __populateEnvironments(self):
114 """ 120 """
115 Private method to get a list of environments and populate the selector. 121 Private method to get a list of environments and populate the selector.
116 """ 122 """
495 @type str 501 @type str
496 """ 502 """
497 self.__updateSearchButton() 503 self.__updateSearchButton()
498 504
499 @pyqtSlot() 505 @pyqtSlot()
506 def on_searchEdit_returnPressed(self):
507 """
508 Private slot initiating a search via a press of the Return key.
509 """
510 self.__search()
511
512 @pyqtSlot()
500 def on_searchButton_clicked(self): 513 def on_searchButton_clicked(self):
501 """ 514 """
502 Private slot handling a press of the search button. 515 Private slot handling a press of the search button.
503 """ 516 """
504 self.__search() 517 self.__search()
683 else: 696 else:
684 score += 1 697 score += 1
685 698
686 return score 699 return score
687 700
701 @pyqtSlot()
702 def on_installButton_clicked(self):
703 """
704 Private slot to handle pressing the Install button..
705 """
706 self.__install()
707
708 @pyqtSlot()
709 def on_installUserSiteButton_clicked(self):
710 """
711 Private slot to handle pressing the Install to User-Site button..
712 """
713 self.__install(userSite=True)
714
715 def __install(self, userSite=False):
716 """
717 Private slot to install the selected packages.
718
719 @param userSite flag indicating to install to the user directory
720 @type bool
721 """
722 venvName = self.environmentsComboBox.currentText()
723 if venvName:
724 packages = []
725 for itm in self.searchResultList.selectedItems():
726 packages.append(itm.text(0).strip())
727 if packages:
728 self.__pip.installPackages(packages, venvName=venvName,
729 userSite=userSite)
730
731 @pyqtSlot()
732 def on_showDetailsButton_clicked(self):
733 """
734 Private slot to handle pressing the Show Details button.
735 """
736 self.__showDetails()
737
738 @pyqtSlot(QTreeWidgetItem, int)
739 def on_searchResultList_itemActivated(self, item, column):
740 """
741 Private slot reacting on an search result item activation.
742
743 @param item reference to the activated item
744 @type QTreeWidgetItem
745 @param column activated column
746 @type int
747 """
748 self.__showDetails(item)
749
750 def __showDetails(self, item=None):
751 """
752 Private slot to show details about the selected package.
753
754 @param item reference to the search result item to show details for
755 @type QTreeWidgetItem
756 """
757 self.showDetailsButton.setEnabled(False)
758 QApplication.setOverrideCursor(Qt.WaitCursor)
759 QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
760
761 self.__detailsData = {}
762
763 if not item:
764 item = self.searchResultList.selectedItems()[0]
765
766 packageVersions = item.data(0, self.SearchVersionRole)
767 if len(packageVersions) == 1:
768 packageVersion = packageVersions[0]
769 elif len(packageVersions) == 0:
770 packageVersion = ""
771 else:
772 packageVersion, ok = QInputDialog.getItem(
773 self,
774 self.tr("Show Package Details"),
775 self.tr("Select the package version:"),
776 packageVersions,
777 0, False)
778 if not ok:
779 return
780
781 packageName = item.text(0)
782 self.__client.call(
783 "release_data",
784 (packageName, packageVersion),
785 lambda d: self.__getPackageDownloadsData(packageName,
786 packageVersion,
787 d),
788 lambda c, s: self.__detailsError(packageName, c, s)
789 )
790
791 def __getPackageDownloadsData(self, packageName, packageVersion, data):
792 """
793 Private method to store the details data and get downloads
794 information.
795
796 @param packageName name of the package
797 @type str
798 @param packageVersion version info
799 @type str
800 @param data result data with package details in the first
801 element
802 @type tuple
803 """
804 if data and data[0]:
805 self.__detailsData = data[0]
806 self.__client.call(
807 "release_urls",
808 (packageName, packageVersion),
809 self.__displayPackageDetails,
810 lambda c, s: self.__detailsError(packageName, c, s)
811 )
812 else:
813 QApplication.restoreOverrideCursor()
814 E5MessageBox.warning(
815 self,
816 self.tr("Search PyPI"),
817 self.tr("""<p>No package details info for <b>{0}</b>"""
818 """ available.</p>""").format(packageName))
819
820 def __displayPackageDetails(self, data):
821 """
822 Private method to display the returned package details.
823
824 @param data result data with downloads information in the first element
825 @type tuple
826 """
827 from .PipPackageDetailsDialog import PipPackageDetailsDialog
828
829 QApplication.restoreOverrideCursor()
830 self.showDetailsButton.setEnabled(True)
831
832 if self.__packageDetailsDialog is not None:
833 self.__packageDetailsDialog.close()
834
835 self.__packageDetailsDialog = \
836 PipPackageDetailsDialog(self.__detailsData, data[0], self)
837 self.__packageDetailsDialog.show()
838
839 def __detailsError(self, packageName, errorCode, errorString):
840 """
841 Private method handling a details error.
842
843 @param packageName name of the package
844 @type str
845 @param errorCode code of the error
846 @type int
847 @param errorString error message
848 @type str
849 """
850 QApplication.restoreOverrideCursor()
851 self.showDetailsButton.setEnabled(True)
852 E5MessageBox.warning(
853 self,
854 self.tr("Search PyPI"),
855 self.tr("""<p>Package details info for <b>{0}</b> could not be"""
856 """ retrieved.</p><p>Reason: {1}</p>""")
857 .format(packageName, errorString)
858 )
859
688 ####################################################################### 860 #######################################################################
689 ## Menu related methods below 861 ## Menu related methods below
690 ####################################################################### 862 #######################################################################
691 863
692 def __initPipMenu(self): 864 def __initPipMenu(self):
693 """ 865 """
694 Private method to create the super menu and attach it to the super 866 Private method to create the super menu and attach it to the super
695 menu button. 867 menu button.
696 """ 868 """
697 self.__pip.initActions() 869 self.__pipMenu = QMenu()
698 870 self.__installPipAct = self.__pipMenu.addAction(
699 self.__pipMenu = self.__pip.initMenu() 871 self.tr("Install Pip"),
872 self.__installPip)
873 self.__installPipUserAct = self.__pipMenu.addAction(
874 self.tr("Install Pip to User-Site"),
875 self.__installPipUser)
876 self.__repairPipAct = self.__pipMenu.addAction(
877 self.tr("Repair Pip"),
878 self.__repairPip)
879 self.__pipMenu.addSeparator()
880 self.__installPackagesAct = self.__pipMenu.addAction(
881 self.tr("Install Packages"),
882 self.__installPackages)
883 self.__installLocalPackageAct = self.__pipMenu.addAction(
884 self.tr("Install Local Package"),
885 self.__installLocalPackage)
886 self.__pipMenu.addSeparator()
887 self.__installRequirementsAct = self.__pipMenu.addAction(
888 self.tr("Install Requirements"),
889 self.__installRequirements)
890 self.__uninstallRequirementsAct = self.__pipMenu.addAction(
891 self.tr("Uninstall Requirements"),
892 self.__uninstallRequirements)
893 self.__generateRequirementsAct = self.__pipMenu.addAction(
894 self.tr("Generate Requirements..."),
895 self.__generateRequirements)
896 self.__pipMenu.addSeparator()
897 # editUserConfigAct
898 self.__pipMenu.addAction(
899 self.tr("Edit User Configuration..."),
900 self.__editUserConfiguration)
901 self.__editVirtualenvConfigAct = self.__pipMenu.addAction(
902 self.tr("Edit Current Virtualenv Configuration..."),
903 self.__editVirtualenvConfiguration)
904 self.__pipMenu.addSeparator()
905 # pipConfigAct
906 self.__pipMenu.addAction(
907 self.tr("Configure..."),
908 self.__pipConfigure)
909
910 self.__pipMenu.aboutToShow.connect(self.__aboutToShowPipMenu)
700 911
701 self.pipMenuButton.setMenu(self.__pipMenu) 912 self.pipMenuButton.setMenu(self.__pipMenu)
913
914 def __aboutToShowPipMenu(self):
915 """
916 Private slot to set the action enabled status.
917 """
918 enable = bool(self.environmentsComboBox.currentText())
919 enablePip = self.__isPipAvailable()
920
921 self.__installPipAct.setEnabled(not enablePip)
922 self.__installPipUserAct.setEnabled(not enablePip)
923 self.__repairPipAct.setEnabled(enablePip)
924
925 self.__installPackagesAct.setEnabled(enablePip)
926 self.__installLocalPackageAct.setEnabled(enablePip)
927
928 self.__installRequirementsAct.setEnabled(enablePip)
929 self.__uninstallRequirementsAct.setEnabled(enablePip)
930 self.__generateRequirementsAct.setEnabled(enablePip)
931
932 self.__editVirtualenvConfigAct.setEnabled(enable)
933
934 @pyqtSlot()
935 def __installPip(self):
936 """
937 Private slot to install pip into the selected environment.
938 """
939 venvName = self.environmentsComboBox.currentText()
940 if venvName:
941 self.__pip.installPip(venvName)
942
943 @pyqtSlot()
944 def __installPipUser(self):
945 """
946 Private slot to install pip into the user site for the selected
947 environment.
948 """
949 venvName = self.environmentsComboBox.currentText()
950 if venvName:
951 self.__pip.installPip(venvName, userSite=True)
952
953 @pyqtSlot()
954 def __repairPip(self):
955 """
956 Private slot to repair the pip installation of the selected
957 environment.
958 """
959 venvName = self.environmentsComboBox.currentText()
960 if venvName:
961 self.__pip.repairPip(venvName)
962
963 @pyqtSlot()
964 def __installPackages(self):
965 """
966 Private slot to install packages to be given by the user.
967 """
968 venvName = self.environmentsComboBox.currentText()
969 if venvName:
970 from .PipPackagesInputDialog import PipPackagesInputDialog
971 dlg = PipPackagesInputDialog(self, self.tr("Install Packages"))
972 if dlg.exec_() == QDialog.Accepted:
973 packages, user = dlg.getData()
974 if packages:
975 self.__pip.installPackages(packages, venvName=venvName,
976 userSite=user)
977
978 @pyqtSlot()
979 def __installLocalPackage(self):
980 """
981 Private slot to install a package available on local storage.
982 """
983 venvName = self.environmentsComboBox.currentText()
984 if venvName:
985 from .PipFileSelectionDialog import PipFileSelectionDialog
986 dlg = PipFileSelectionDialog(self, "package")
987 if dlg.exec_() == QDialog.Accepted:
988 package, user = dlg.getData()
989 if package and os.path.exists(package):
990 self.__pip.installPackages([package], venvName=venvName,
991 userSite=user)
992
993 @pyqtSlot()
994 def __installRequirements(self):
995 """
996
997 """
998 # TODO: call pip.installRequirements()
999
1000 @pyqtSlot()
1001 def __uninstallRequirements(self):
1002 """
1003
1004 """
1005 # TODO: call pip.uninstallRequirements()
1006
1007 @pyqtSlot()
1008 def __generateRequirements(self):
1009 """
1010 Private slot to generate the contents for a requirements file.
1011 """
1012 # TODO: modify to get selected environment
1013 from .PipFreezeDialog import PipFreezeDialog
1014 self.__freezeDialog = PipFreezeDialog(self)
1015 self.__freezeDialog.show()
1016 self.__freezeDialog.start()
1017
1018 @pyqtSlot()
1019 def __editUserConfiguration(self):
1020 """
1021 Private slot to edit the user configuration.
1022 """
1023 self.__editConfiguration()
1024
1025 @pyqtSlot()
1026 def __editVirtualenvConfiguration(self):
1027 """
1028 Private slot to edit the current virtualenv configuration.
1029 """
1030 # TODO: modify to get selected environment
1031 self.__editConfiguration(virtualenv=True)
1032
1033 def __editConfiguration(self, virtualenv=False):
1034 """
1035 Private method to edit a configuration.
1036
1037 @param virtualenv flag indicating to edit the current virtualenv
1038 configuration file
1039 @type bool
1040 """
1041 # TODO: modify to use venvName
1042 from QScintilla.MiniEditor import MiniEditor
1043 if virtualenv:
1044 cfgFile = self.__getVirtualenvConfig()
1045 if not cfgFile:
1046 return
1047 else:
1048 cfgFile = self.__getUserConfig()
1049 cfgDir = os.path.dirname(cfgFile)
1050 if not cfgDir:
1051 E5MessageBox.critical(
1052 None,
1053 self.tr("Edit Configuration"),
1054 self.tr("""No valid configuration path determined."""
1055 """ Is a virtual environment selected? Aborting"""))
1056 return
1057
1058 try:
1059 if not os.path.isdir(cfgDir):
1060 os.makedirs(cfgDir)
1061 except OSError:
1062 E5MessageBox.critical(
1063 None,
1064 self.tr("Edit Configuration"),
1065 self.tr("""No valid configuration path determined."""
1066 """ Is a virtual environment selected? Aborting"""))
1067 return
1068
1069 if not os.path.exists(cfgFile):
1070 try:
1071 f = open(cfgFile, "w")
1072 f.write("[global]\n")
1073 f.close()
1074 except (IOError, OSError):
1075 # ignore these
1076 pass
1077
1078 # check, if the destination is writeable
1079 if not os.access(cfgFile, os.W_OK):
1080 E5MessageBox.critical(
1081 None,
1082 self.tr("Edit Configuration"),
1083 self.tr("""No valid configuartion path determined."""
1084 """ Is a virtual environment selected? Aborting"""))
1085 return
1086
1087 self.__editor = MiniEditor(cfgFile, "Properties")
1088 self.__editor.show()
1089
1090 def __pipConfigure(self):
1091 """
1092 Private slot to open the configuration page.
1093 """
1094 e5App().getObject("UserInterface").showPreferences("pipPage")

eric ide

mercurial