src/eric7/PipInterface/PipPackageDetailsDialog.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show details about a package.
8 """
9
10 from PyQt6.QtCore import pyqtSlot, Qt, QLocale
11 from PyQt6.QtWidgets import (
12 QDialog, QDialogButtonBox, QTreeWidgetItem, QLabel, QHeaderView,
13 QAbstractButton
14 )
15
16 from .Ui_PipPackageDetailsDialog import Ui_PipPackageDetailsDialog
17
18
19 class PipPackageDetailsDialog(QDialog, Ui_PipPackageDetailsDialog):
20 """
21 Class implementing a dialog to show details about a package.
22 """
23 ButtonInstall = 1
24 ButtonRemove = 2
25 ButtonUpgrade = 4
26
27 def __init__(self, detailsData, buttonsMode=0, parent=None):
28 """
29 Constructor
30
31 @param detailsData package details
32 @type dict
33 @param buttonsMode flags telling which convenience buttons to enable
34 (defaults to 0)
35 @type int (optional)
36 @param parent reference to the parent widget (defaults to None)
37 @type QWidget (optional)
38 """
39 super().__init__(parent)
40 self.setupUi(self)
41 self.setWindowFlags(Qt.WindowType.Window)
42
43 self.__pipWidget = parent
44
45 self.__installButton = self.buttonBox.addButton(
46 self.tr("Install"), QDialogButtonBox.ButtonRole.ActionRole)
47 self.__removeButton = self.buttonBox.addButton(
48 self.tr("Uninstall"), QDialogButtonBox.ButtonRole.ActionRole)
49 self.__upgradeButton = self.buttonBox.addButton(
50 self.tr("Upgrade"), QDialogButtonBox.ButtonRole.ActionRole)
51
52 self.__locale = QLocale()
53 self.__packageTypeMap = {
54 "sdist": self.tr("Source"),
55 "bdist_wheel": self.tr("Python Wheel"),
56 "bdist_egg": self.tr("Python Egg"),
57 "bdist_wininst": self.tr("MS Windows Installer"),
58 "bdist_msi": self.tr("MS Windows Installer"),
59 "bdist_rpm": self.tr("Unix Installer"),
60 "bdist_deb": self.tr("Unix Installer"),
61 "bdist_dumb": self.tr("Archive"),
62 }
63 self.__packageName = detailsData["info"]["name"]
64
65 self.__populateDetails(detailsData["info"])
66 self.__populateDownloadUrls(detailsData["urls"])
67 self.__populateRequiresProvides(detailsData["info"])
68
69 self.__installButton.setEnabled(buttonsMode & self.ButtonInstall)
70 self.__removeButton.setEnabled(buttonsMode & self.ButtonRemove)
71 self.__upgradeButton.setEnabled(buttonsMode & self.ButtonUpgrade)
72
73 def __populateDetails(self, detailsData):
74 """
75 Private method to populate the details tab.
76
77 @param detailsData package details
78 @type dict
79 """
80 self.packageNameLabel.setText(
81 "<h1>{0} {1}</h1".format(self.__sanitize(detailsData["name"]),
82 self.__sanitize(detailsData["version"])))
83 self.summaryLabel.setText(
84 self.__sanitize(detailsData["summary"][:240]))
85 self.descriptionEdit.setPlainText(
86 self.__sanitize(detailsData["description"]))
87 self.authorLabel.setText(self.__sanitize(detailsData["author"]))
88 self.authorEmailLabel.setText(
89 '<a href="mailto:{0}">{0}</a>'.format(
90 self.__sanitize(detailsData["author_email"])))
91 self.licenseLabel.setText(self.__sanitize(detailsData["license"]))
92 self.platformLabel.setText(self.__sanitize(detailsData["platform"]))
93 self.homePageLabel.setText(
94 '<a href="{0}">{0}</a>'.format(
95 self.__sanitize(detailsData["home_page"], forUrl=True)))
96 self.packageUrlLabel.setText(
97 '<a href="{0}">{0}</a>'.format(
98 self.__sanitize(detailsData["package_url"], forUrl=True)))
99 self.releaseUrlLabel.setText(
100 '<a href="{0}">{0}</a>'.format(
101 self.__sanitize(detailsData["release_url"], forUrl=True)))
102 self.docsUrlLabel.setText(
103 '<a href="{0}">{0}</a>'.format(
104 self.__sanitize(detailsData["docs_url"], forUrl=True)))
105 self.classifiersList.addItems(detailsData["classifiers"])
106
107 self.buttonBox.button(
108 QDialogButtonBox.StandardButton.Close).setDefault(True)
109 self.buttonBox.button(
110 QDialogButtonBox.StandardButton.Close).setFocus(
111 Qt.FocusReason.OtherFocusReason)
112
113 def __populateDownloadUrls(self, downloadsData):
114 """
115 Private method to populate the download URLs tab.
116
117 @param downloadsData downloads information
118 @type dict
119 """
120 index = self.infoWidget.indexOf(self.urls)
121 if downloadsData:
122 self.infoWidget.setTabEnabled(index, True)
123 for download in downloadsData:
124 itm = QTreeWidgetItem(self.downloadUrlsList, [
125 "",
126 self.__packageTypeMap[download["packagetype"]]
127 if download["packagetype"] in self.__packageTypeMap
128 else "",
129 download["python_version"]
130 if download["python_version"] != "source"
131 else "",
132 self.__formatUploadDate(download["upload_time"]),
133 self.__formatSize(download["size"]),
134 ])
135 pgpLink = (
136 ' (<a href="{0}">pgp</a>)'.format(download["url"] + ".asc")
137 if download["has_sig"] else
138 ""
139 )
140 urlLabel = QLabel('<a href="{0}#md5={2}">{1}</a>{3}'.format(
141 download["url"], download["filename"],
142 download["md5_digest"], pgpLink))
143 urlLabel.setTextInteractionFlags(
144 Qt.TextInteractionFlag.LinksAccessibleByMouse)
145 urlLabel.setOpenExternalLinks(True)
146 self.downloadUrlsList.setItemWidget(itm, 0, urlLabel)
147 header = self.downloadUrlsList.header()
148 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents)
149 else:
150 self.infoWidget.setTabEnabled(index, False)
151
152 def __populateRequiresProvides(self, detailsData):
153 """
154 Private method to populate the requires/provides tab.
155
156 @param detailsData package details
157 @type dict
158 """
159 populatedItems = 0
160
161 if "requires" in detailsData and detailsData["requires"]:
162 self.requiredPackagesList.addItems(detailsData["requires"])
163 populatedItems += len(detailsData["requires"])
164 if "requires_dist" in detailsData and detailsData["requires_dist"]:
165 self.requiredDistributionsList.addItems(
166 detailsData["requires_dist"])
167 populatedItems += len(detailsData["requires_dist"])
168 if "provides" in detailsData and detailsData["provides"]:
169 self.providedPackagesList.addItems(detailsData["provides"])
170 populatedItems += len(detailsData["provides"])
171 if "provides_dist" in detailsData and detailsData["provides_dist"]:
172 self.providedDistributionsList.addItems(
173 detailsData["provides_dist"])
174 populatedItems += len(detailsData["provides_dist"])
175
176 index = self.infoWidget.indexOf(self.requires)
177 self.infoWidget.setTabEnabled(index, populatedItems > 0)
178
179 def __sanitize(self, text, forUrl=False):
180 """
181 Private method to clean-up the given text.
182
183 @param text raw text
184 @type str
185 @param forUrl flag indicating to sanitize an URL text
186 @type bool
187 @return processed text
188 @rtype str
189 """
190 if text == "UNKNOWN" or text is None:
191 text = ""
192 elif text == "any":
193 text = self.tr("any")
194 if forUrl and (
195 not isinstance(text, str) or
196 not text.startswith(("http://", "https://", "ftp://"))
197 ):
198 # ignore if the schema is not one of the listed ones
199 text = ""
200
201 return text
202
203 def __formatUploadDate(self, datetime):
204 """
205 Private method to format the upload date.
206
207 @param datetime upload date and time
208 @type xmlrpc.DateTime or str
209 @return formatted date string
210 @rtype str
211 """
212 if isinstance(datetime, str):
213 return datetime.split("T")[0]
214 else:
215 date = datetime.value.split("T")[0]
216 return "{0}-{1}-{2}".format(date[:4], date[4:6], date[6:])
217
218 def __formatSize(self, size):
219 """
220 Private slot to format the size.
221
222 @param size size to be formatted
223 @type int
224 @return formatted size
225 @rtype str
226 """
227 unit = ""
228 if size < 1024:
229 unit = self.tr("B")
230 elif size < 1024 * 1024:
231 size /= 1024
232 unit = self.tr("KB")
233 elif size < 1024 * 1024 * 1024:
234 size /= 1024 * 1024
235 unit = self.tr("MB")
236 else:
237 size /= 1024 * 1024 * 1024
238 unit = self.tr("GB")
239 return self.tr("{0:.1f} {1}", "value, unit").format(size, unit)
240
241 @pyqtSlot(QAbstractButton)
242 def on_buttonBox_clicked(self, button):
243 """
244 Private slot handling the user pressing an action button.
245
246 @param button button activated by the user
247 @type QAbstractButton
248 """
249 if button is self.__installButton:
250 self.__pipWidget.executeInstallPackages([self.__packageName])
251 self.__installButton.setEnabled(False)
252 self.__removeButton.setEnabled(True)
253 self.__upgradeButton.setEnabled(False)
254 self.raise_()
255 elif button is self.__removeButton:
256 self.__pipWidget.executeUninstallPackages([self.__packageName])
257 self.__installButton.setEnabled(True)
258 self.__removeButton.setEnabled(False)
259 self.__upgradeButton.setEnabled(False)
260 self.raise_()
261 elif button is self.__upgradeButton:
262 self.__pipWidget.executeUpgradePackages([self.__packageName])
263 self.__installButton.setEnabled(False)
264 self.__removeButton.setEnabled(True)
265 self.__upgradeButton.setEnabled(False)
266 self.raise_()

eric ide

mercurial