class WPAPI(QObject): done = Signal(list) def __init__(self): QObject.__init__(self) self._nam = QNetworkAccessManager(self) self._nam.finished.connect(self._on_fetched) def fetch(self, page=1, perpage=10): url = QUrl(WPAPI_ROOT.format(page=page, perpage=perpage)) request = QNetworkRequest(url) self._nam.get(request) def _on_fetched(self, reply): content = reply.readAll() try: js = json.loads(bytes(content).decode('utf-8')) posts = [] for post in js: content = { 'title': post.get('title', {}).get('rendered'), 'body': post.get('content', {}).get('rendered'), 'date': post.get('date'), 'excerpt': post.get('excerpt', {}).get('rendered'), 'author': post.get('_embedded', {}).get('author') } posts.append(content) self.done.emit(posts) except Exception: pass
def __init__(self, *args, **kargs): super().__init__(*args, **kargs) # lazy creation of the NetworkManager global _manager if _manager is None: _manager = QNetworkAccessManager() # open the destination file for writing if self.dest and self.dest != '::mem::': try: self._dest_fp = open(self.dest, 'wb') except OSError: self._notify_done(False) return else: self._dest_fp = None # build and send the GET request request = QNetworkRequest(self.url) if self._headers is not None: for key in self._headers: request.setHeader(key, self._headers[key]) self._reply = _manager.get(request) self._reply.finished.connect(self._finished_cb) self._reply.downloadProgress.connect(self._progress_cb) if self.dest != '::mem::': self._reply.readyRead.connect(self._data_ready_cb)
def start_fetch(self, network_manager: QtNetwork.QNetworkAccessManager): """Asynchronously begin the network access. Intended as a set-and-forget black box for downloading files.""" self.request = QtNetwork.QNetworkRequest(QtCore.QUrl(self.url)) self.request.setAttribute( QtNetwork.QNetworkRequest.RedirectPolicyAttribute, QtNetwork.QNetworkRequest.UserVerifiedRedirectPolicy, ) self.fetch_task = network_manager.get(self.request) self.fetch_task.finished.connect(self.resolve_fetch) self.fetch_task.redirected.connect(self.on_redirect) self.fetch_task.sslErrors.connect(self.on_ssl_error)
def __init__(self, row, col, img_url, parent=None): super(Tile, self).__init__(parent=parent) self.row = row self.col = col self.setGeometry(0, 0, 200, 200) self.setMargin(10) self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.mousePressEvent = lambda event: self.handle_mouse_pressed(event) self.setStyleSheet("border: 1px dotted gray;") # load the image manager = QNetworkAccessManager(self) manager.finished[QNetworkReply].connect(self.disp_image) manager.get(QNetworkRequest(QUrl("https://images.dog.ceo/breeds/groenendael/n02105056_6127.jpg"))) # default pixmap self.default_pixmap = QPixmap(200, 200) self.default_pixmap.fill(Qt.gray) self.setPixmap(self.default_pixmap) # second pixmap self.dog_pixmap = QPixmap(200, 200) self.anim = QVariantAnimation() self.anim.setDuration(500) self.anim.setEasingCurve(QEasingCurve.Linear) self.anim.valueChanged.connect(self.anim_value_changed) self.anim.setStartValue(float(0)) self.anim.setEndValue(float(180)) self.anim1 = QVariantAnimation() self.anim1.setDuration(500) self.anim1.setEasingCurve(QEasingCurve.Linear) self.anim1.valueChanged.connect(self.anim1_value_changed) self.anim1.setStartValue(float(180)) self.anim1.setEndValue(float(0)) self.resize(200, 200) self.anim1.start()
def __init__(self, manager: QNetworkAccessManager, url: str, output_url: str): super(FileDownload, self).__init__(None) request = QNetworkRequest(url) self.output_url = output_url self.output = QFile(self.output_url) self.logger = create_logger(__name__) if not self.output.open(QIODevice.WriteOnly): self.logger.info( "Could not open: {url}".format(url=self.output_url)) return self.current_download = manager.get(request) self.current_download_progress = FileDownloadProgress() self.current_download.downloadProgress.connect( self.current_download_progress.update) self.current_download.readyRead.connect(self.saveFile) self.current_download.finished.connect(self.download_finished)
class DownloadDialog(QDialog): """Summary A dialog to download file and display progression Attributes: source (QUrl): url of file to download destination (QDir): destination folder of downloaded file """ def __init__(self, parent=None): super().__init__(parent) self.file_label = QLabel() self.progress = QProgressBar() self.info_label = QLabel() self.btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.net = QNetworkAccessManager() font = QFont() font.setBold(True) self.file_label.setFont(font) v_layout = QVBoxLayout() v_layout.addWidget(self.file_label) v_layout.addWidget(self.progress) v_layout.addWidget(self.info_label) v_layout.addStretch() v_layout.addWidget(self.btn_box) self.btn_box.accepted.connect(self.close) self.btn_box.rejected.connect(self.cancel) self.btn_box.button(QDialogButtonBox.Ok).setVisible(False) self.setLayout(v_layout) self.setFixedSize(450, 150) self.setWindowTitle(self.tr("Download file")) def set_source(self, url: QUrl): """Set file url to download Args: url (QUrl) """ self.source = url self.file_label.setText(self.source.fileName()) def set_destination(self, directory: QDir): """Set folder path where download the file Args: directory (QDir) """ self.destination = directory def start(self): """ Start downloading the file specify by set_source """ filepath = self.destination.absoluteFilePath(self.source.fileName()) if QFile(filepath).exists(): QFile.remove(filepath) self._file = QFile(filepath) # open the file to write in if self._file.open(QIODevice.WriteOnly): print("open file", filepath) # Create a Qt Request request = QNetworkRequest() request.setUrl(self.source) self.time = QTime.currentTime() self.reply = self.net.get(request) # Connect reply to different slots self.reply.downloadProgress.connect(self.on_update_progress) self.reply.finished.connect(self.on_finished) self.reply.error.connect(self.on_error) def cancel(self): """Cancel download """ if hasattr(self, "reply"): self.reply.abort() self._file.remove() self.close() @Slot(int, int) def on_update_progress(self, read, total): """This methods is called by self.reply.downloadProgress signal Args: read (int): Number of bytes readed total (int): Total bytes to download """ if read <= 0: return if self.reply.error() != QNetworkReply.NoError: return self._file.write(self.reply.readAll()) # compute speed duration = self.time.secsTo(QTime.currentTime()) + 1 speed = read / duration remaining = (total - read) / speed h_remaining = QTime(0, 0, 0, 0).addSecs(remaining).toString() h_total = self.human_readable_bytes(total) h_read = self.human_readable_bytes(read) h_speed = self.human_readable_bytes(speed) + "/sec" self.info_label.setText( f"Time remaining {h_remaining} - {h_read} of {h_total} ({h_speed})" ) # Set progression self.progress.setRange(0, total) self.progress.setValue(read) @Slot() def on_finished(self): """This methods is called by self.reply.finished signal """ if self.reply.error() == QNetworkReply.NoError: self._file.close() self.reply.deleteLater() self.btn_box.button(QDialogButtonBox.Ok).setVisible(True) @Slot(QNetworkReply.NetworkError) def on_error(self, err: QNetworkReply.NetworkError): """This method is called by self.reply.error signal Args: err (QNetworkReply.NetworkError) """ self.reply.deleteLater() def human_readable_bytes(self, num, suffix="B"): for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, "Yi", suffix)
class SlippyMap(QObject): updated = Signal(QRect) def __init__(self, parent=None): """ :param parent: """ super(SlippyMap, self).__init__(parent) self._offset = QPoint() self._tiles_rectangle = QRect() self._tile_pixmaps = {} # Point(x, y) to QPixmap mapping self._manager = QNetworkAccessManager() self._url = QUrl() # public vars self.width = 400 self.height = 300 self.zoom = 4 self.latitude = 59.9138204 self.longitude = 10.7387413 self._emptyTile = QPixmap(TDIM, TDIM) self._emptyTile.fill(Qt.lightGray) self.request = QNetworkRequest() self.cache = QNetworkDiskCache() self.cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self._manager.setCache(self.cache) self._manager.finished.connect(self.handle_network_data) def invalidate(self): """ :return: """ if self.width <= 0 or self.height <= 0: return ct = tile_for_coordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM) yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM) # first tile vertical and horizontal xa = (xp + TDIM - 1) / TDIM ya = (yp + TDIM - 1) / TDIM xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self._offset = QPoint(int(xp - xa * TDIM), int(yp - ya * TDIM)) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / TDIM ye = int(ty) + (self.height - yp - 1) / TDIM # build a rect self._tiles_rectangle = QRect(int(xs), int(ys), int(xe - xs + 1), int(ye - ys + 1)) if self._url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, p: QPainter, rect: QRect): """ Render a tile :param p: QPainter instance, place where to pain the tiles :param rect: QRect instance, dimensions of the painter (the window that renders the tiles) :return: Nothing """ rx = range(self._tiles_rectangle.width()) ry = range(self._tiles_rectangle.height()) for x, y in product(rx, ry): tp = Point(x + self._tiles_rectangle.left(), y + self._tiles_rectangle.top()) box = self.tile_rectangle(tp) if rect.intersects(box): p.drawPixmap(box, self._tile_pixmaps.get(tp, self._emptyTile)) def pan(self, delta: QPoint): """ Move the map :param delta: x, y delta as a QPoint instance :return: Nothing """ dx = QPointF(delta) / float(TDIM) center = tile_for_coordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitude_from_tile(center.y(), self.zoom) self.longitude = longitude_from_tile(center.x(), self.zoom) self.invalidate() # slots def handle_network_data(self, reply: QNetworkReply): """ This function is called automatically by a QNetworkAccessManager object (self._manager) :param reply: QNetworkReply instance :return: Nothing """ img = QImage() tp = Point(reply.request().attribute(QNetworkRequest.User)) url = reply.url() if not reply.error(): # if there was no url error... if img.load(reply, None): # if the image loading went well... self._tile_pixmaps[tp] = QPixmap.fromImage( img) # store the image in the tiles dictionary reply.deleteLater() self.updated.emit(self.tile_rectangle(tp)) # purge unused tiles bound = self._tiles_rectangle.adjusted(-2, -2, 2, 2) for tp in list(self._tile_pixmaps.keys()): if not bound.contains(tp): del self._tile_pixmaps[tp] self.download() def download(self): """ Download tile :return: Nothing """ grab = None rx = range(self._tiles_rectangle.width()) ry = range(self._tiles_rectangle.height()) for x, y in product(rx, ry): tp = Point(self._tiles_rectangle.topLeft() + QPoint(x, y)) if tp not in self._tile_pixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % ( self.zoom, grab.x(), grab.y()) self._url = QUrl(path) self.request = QNetworkRequest() self.request.setUrl(self._url) self.request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') self.request.setAttribute(QNetworkRequest.User, grab) self._manager.get(self.request) print('downloading z:', self.zoom, 'x:', grab.x(), 'y:', grab.y()) def tile_rectangle(self, tp: Point): """ Get tile rectangle :param tp: Tile point :return: QRect instance """ t = tp - self._tiles_rectangle.topLeft() x = t.x() * TDIM + self._offset.x() y = t.y() * TDIM + self._offset.y() return QRect(x, y, TDIM, TDIM)
class SlippyMap(QObject): updated = Signal(QRect) def __init__(self, parent=None): super(SlippyMap, self).__init__(parent) self._offset = QPoint() self._tilesRect = QRect() self._tilePixmaps = {} # Point(x, y) to QPixmap mapping self._manager = QNetworkAccessManager() self._url = QUrl() # public vars self.width = 400 self.height = 300 self.zoom = 15 self.latitude = 59.9138204 self.longitude = 10.7387413 self._emptyTile = QPixmap(TDIM, TDIM) self._emptyTile.fill(Qt.lightGray) self.request = QNetworkRequest() self.cache = QNetworkDiskCache() self.cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self._manager.setCache(self.cache) self._manager.finished.connect(self.handleNetworkData) def invalidate(self): if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM) yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM) # first tile vertical and horizontal xa = (xp + TDIM - 1) / TDIM ya = (yp + TDIM - 1) / TDIM xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / TDIM ye = int(ty) + (self.height - yp - 1) / TDIM # build a rect self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self._url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, p, rect): for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(x + self._tilesRect.left(), y + self._tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): p.drawPixmap(box, self._tilePixmaps.get(tp, self._emptyTile)) def pan(self, delta): dx = QPointF(delta) / float(TDIM) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() # slots def handleNetworkData(self, reply): img = QImage() tp = Point(reply.request().attribute(QNetworkRequest.User)) url = reply.url() if not reply.error(): if img.load(reply, None): self._tilePixmaps[tp] = QPixmap.fromImage(img) reply.deleteLater() self.updated.emit(self.tileRect(tp)) # purge unused tiles bound = self._tilesRect.adjusted(-2, -2, 2, 2) for tp in list(self._tilePixmaps.keys()): if not bound.contains(tp): del self._tilePixmaps[tp] self.download() def download(self): grab = None for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(self._tilesRect.topLeft() + QPoint(x, y)) if tp not in self._tilePixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % ( self.zoom, grab.x(), grab.y()) self._url = QUrl(path) self.request = QNetworkRequest() self.request.setUrl(self._url) self.request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') self.request.setAttribute(QNetworkRequest.User, grab) self._manager.get(self.request) def tileRect(self, tp): t = tp - self._tilesRect.topLeft() x = t.x() * TDIM + self._offset.x() y = t.y() * TDIM + self._offset.y() return QRect(x, y, TDIM, TDIM)
class UpdatePage(QLabel): def __init__(self, *args, **kwargs): super(UpdatePage, self).__init__(*args, *kwargs) self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle('分析决策系统自动更新程序') self.request_stack = list() self.update_error = False self.current_count = 0 self.update_count = 0 self._pressed = False self._mouse_pos = None self.sys_bit = "32" if sys.maxsize < 2**32 else "64" self._server = "" self.network_manager = QNetworkAccessManager(self) icon_path = os.path.join(BASE_DIR, "icons/app.png") pix_path = os.path.join(BASE_DIR, "images/update_bg.png") self.setWindowIcon(QIcon(icon_path)) self.setPixmap(QPixmap(pix_path)) self.red = QPalette() self.red.setColor(QPalette.WindowText, Qt.red) self.blue = QPalette() self.blue.setColor(QPalette.WindowText, Qt.blue) font = QFont() font.setPointSize(16) font.setBold(True) font.setWeight(75) self.setFixedSize(500, 200) self.setScaledContents(True) self.setFont(font) self.show_text = QLabel("系统正在下载新版本文件...", self) self.show_text.setFont(font) self.show_text.setFixedSize(self.width(), self.height()) self.show_text.setAlignment(Qt.AlignCenter) self.show_text.setPalette(self.blue) self.update_process_bar = QProgressBar(self) self.update_process_bar.setGeometry(1, 160, 498, 12) self.update_process_bar.setObjectName('processBar') self.setStyleSheet(""" #processBar{ text-align:center; font-size: 12px; font-weight:100; border: 1px solid #77d333; border-radius: 5px; background-color:none; } #processBar::chunk { background-color: #77d363; border-radius: 3px; margin:2px } """) self._updating() def mousePressEvent(self, event): super(UpdatePage, self).mousePressEvent(event) if event.button() == Qt.LeftButton: self._pressed = True self._mouse_pos = event.pos() def mouseReleaseEvent(self, event): super(UpdatePage, self).mouseReleaseEvent(event) self._pressed = False self._mouse_pos = None def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton and self._mouse_pos: self.move(self.mapToGlobal(event.pos() - self._mouse_pos)) event.accept() def _updating(self): """ 更新 """ # 读取更新的文件信息 new_update_file = os.path.join( BASE_DIR, "classini/for_update_{}.json".format(self.sys_bit)) old_update_file = os.path.join( BASE_DIR, "classini/update_{}.json".format(self.sys_bit)) if not os.path.exists(new_update_file) or not os.path.exists( old_update_file): self.show_text.setText("更新信息文件丢失...") self.show_text.setPalette(self.red) return with open(new_update_file, "r", encoding="utf-8") as new_f: new_json = json.load(new_f) with open(old_update_file, "r", encoding="utf-8") as old_f: old_json = json.load(old_f) self._server = new_json["SERVER"] for_update_dict = new_json["FILES"] old_dict = old_json["FILES"] self.update_count = len(for_update_dict) self.update_process_bar.setMaximum(self.update_count) for file_path, file_hash in for_update_dict.items(): old_hash = old_dict.get(file_path, None) if old_hash is not None and old_hash == file_hash: # print(file_path, "hash相等") self.current_count += 1 self.update_process_bar.setValue(self.current_count) if self.current_count >= self.update_count: self.update_finished_restart_app() continue # 生成请求对象 self.generate_requests(file_path) # 执行下载 self.exec_downloading() def received_file(self): """ 接收到文件 """ reply = self.sender() # 从路径中解析要保存的位置 request_url = reply.request().url().url() split_ = request_url.split("/{}/".format(self.sys_bit)) save_file_path = os.path.join(BASE_DIR, split_[1]) # 文件夹不存在创建 save_dir = os.path.split(save_file_path)[0] if not os.path.exists(save_dir): os.makedirs(save_dir) file_data = reply.readAll() if reply.error(): # print("更新错误", reply.error()) self.update_error = True file_obj = QFile(save_file_path) is_open = file_obj.open(QFile.WriteOnly) if is_open: file_obj.write(file_data) file_obj.close() else: self.update_error = True self.current_count += 1 self.update_process_bar.setValue(self.current_count) reply.deleteLater() if self.current_count >= self.update_count: self.update_finished_restart_app() def generate_requests(self, file_path): """ 生成请求对象 """ url = self._server + "{}/{}".format(self.sys_bit, file_path) self.request_stack.append(QNetworkRequest(url=QUrl(url))) def exec_downloading(self): """ 开始文件下载 """ for request_item in self.request_stack: reply = self.network_manager.get(request_item) reply.finished.connect(self.received_file) def update_finished_restart_app(self): self.show_text.setText("更新完成!") if not self.update_error: # 下载完毕后且之间无发生过错误,将新文件内容复制到旧文件,真正完成更新 new_update_file = os.path.join( BASE_DIR, "classini/for_update_{}.json".format(self.sys_bit)) old_update_file = os.path.join( BASE_DIR, "classini/update_{}.json".format(self.sys_bit)) with open(new_update_file, "r", encoding="utf-8") as new_f: new_json = json.load(new_f) del new_json["SERVER"] with open(old_update_file, "w", encoding="utf-8") as old_f: json.dump(new_json, old_f, indent=4, ensure_ascii=False) os.remove(new_update_file) # 重新启动主程序 script_path = os.path.join(BASE_DIR, "ADClient.exe") if os.path.exists(script_path): Popen(script_path, shell=False) self.close() sys.exit() else: self.show_text.setText("更新成功\n执行文件不存在!") self.show_text.setPalette(self.red)