eric6/PipInterface/PipPackageDetailsDialog.py

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

eric ide

mercurial