src/eric7/PipInterface/PipPackageDetailsDialog.py

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

eric ide

mercurial