Output of youtube-dl using QProcess - python

I am so new to python and am in process of learning this powerful language. I managed to write the following script. It does get a partial output ( only two lines of it ) the I don't know what is going wrong! Please help me.
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import (QProcess,QRect,SIGNAL,SLOT,QString,QStringList,qDebug)
from PyQt4.QtGui import (QMainWindow,QWidget,QPushButton,QTextEdit,QApplication)
class YTDL (QtGui.QMainWindow):
def __init__ (self,parent=None):
super(YTDL,self).__init__(parent)
self.resize(400,300)
self.setWindowTitle("Youtube-dl output using QProcess")
self.__init_Components()
self.__ui_event_handler()
def __init_Components(self):
self.proc = QProcess()
self.cw = QWidget(self)
self.btn = QPushButton(self.cw)
self.btn.setText("Run")
self.btn.setGeometry(QRect(270,10,110,27))
self.te = QTextEdit(self.cw)
self.te.setReadOnly(True)
self.te.setOverwriteMode(False)
self.te.setGeometry(QRect(10,40,380,170))
self.setCentralWidget(self.cw)
def __ui_event_handler(self):
self.connect(self.btn, SIGNAL('clicked()'),self.Button_Clicked)
def Button_Clicked(self):
args = '-ct -f 18 --extract-audio --audio-quality 320k --audio-format mp3 -k http://www.youtube.com/watch?v=OiPO_TAAZPc'
cmd = 'youtube-dl'
self.proc.setWorkingDirectory("~/Videos/Folder1")
self.connect(self.proc, SIGNAL('readyRead()'),self._read)
self.proc.setOpenMode(self.proc.ReadWrite)
self.proc.start(cmd ,args)
if not self.proc.waitForStarted():
exit(1)
def _read(self):
s = self.proc.readAllStandardOutput()
qDebug (s)
print (s)
self.te.append(QString(s))
def main():
import sys
app = QApplication(sys.argv)
ytdl = YTDL()
ytdl.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

I think I figured it out myself. Here is an all improved version below. If there is something I need to improve upon, I will welcome any recommendations.
class YTDL (QtGui.QMainWindow):
def init (self,parent=None):
super(YTDL,self).init(parent)
self.resize(400,350)
self.setWindowTitle("Youtube-dl output using QProcess")
self.__init_Components()
self.__ui_event_handler()
def __init_Components(self):
self.proc = QProcess()
self.cw = QWidget(self)
self.btn = QPushButton(self.cw)
self.btn.setText("Run")
self.btn.setGeometry(QRect(270,10,110,27))
self.te = QTextEdit(self.cw)
self.te.setReadOnly(True)
self.te.setOverwriteMode(False)
self.te.setGeometry(QRect(10,40,380,170))
self.progbar = QProgressBar(self.cw)
self.progbar.setGeometry(QRect(10,220,380,18))
self.progbar.setRange(0,100)
self.progbar.setValue(0)
self.progbar.show()
self.setCentralWidget(self.cw)
def __ui_event_handler(self):
self.connect(self.btn, SIGNAL('clicked()'),self.Button_Clicked)
self.connect(self.proc, SIGNAL('readyReadStandardOutput()'),self._read)
self.connect(self.proc, SIGNAL('readyReadStandardError()'),self._readError)
def Button_Clicked(self):
args = "-ct -f 18 --extract-audio --audio-quality 320k --audio-format mp3 -k http://www.youtube.com/watch?v=SjUrib_Gh0Y"
cmd = "youtube-dl"
cmd = cmd + " " + args
print (cmd)
self.proc.setWorkingDirectory("~/Videos/Folder1")
self.proc.setOpenMode(self.proc.ReadWrite)
self.proc.start(cmd)
self.proc.waitForStarted()
def _read(self):
s = str(self.proc.readAllStandardOutput())
download_progress_exp = re.compile(r'.\d+\.\d+\%', re.MULTILINE)
progbarresult = download_progress_exp.findall(s)
i = 0
if progbarresult != []:
for i in range(0,len(progbarresult)):
self.progbar.setValue(float(progbarresult[i].strip("%")))
self.te.append(QString(s))
def _readError(self):
self.te.append(str(self.proc.readAllStandardError()))

Related

Why function defined in class is not visible in other fragments of code?

I am playing with python, being completely new at that. I wrote my first "serious" piece of code using tkinter and beautifulsoup and stuff and it worked. Now, trying to expand my knowledge I am re-writing it using pyqt5 and trying to use classes instead of "spaghetti" code.
My program in general works, it reads website, parses the html code with BeautifulSoup, gets required lines, etc. I used some "calculator" tutorial to base it on and with many trials and errors I made it work. Code below:
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout, QPushButton, QFileDialog, QMainWindow
from PyQt5.QtCore import Qt, QDate, QTimer, QEventLoop
from PyQt5.QtGui import QIcon, QPixmap
import sys
import os
import requests
from bs4 import BeautifulSoup
from operator import itemgetter
ERROR_MSG = 'ERROR'
class BinColUI(QMainWindow):
def createLabelTop(self):
self.label_top = QLabel('PLEASE WAIT')
self.label_top.setAlignment(Qt.AlignCenter)
self.label_top.setStyleSheet("font: 14pt Bahnschrift; color: yellow")
self.generalLayout.addWidget(self.label_top, alignment=Qt.AlignCenter)
def createLabelBot(self):
self.label_bot = QLabel('PLEASE WAIT')
self.label_bot.setAlignment(Qt.AlignCenter)
self.label_bot.setStyleSheet("font: 14pt Bahnschrift; color: yellow")
self.generalLayout.addWidget(self.label_bot, alignment=Qt.AlignCenter)
def setLabels(self, texttop, textbot):
self.label_top.setText(texttop)
self.label_bot.setText(textbot)
def createLabelImg(self):
label_img = QLabel()
label_img.setFixedSize(self.window().width(), 300)
label_img.setAlignment(Qt.AlignCenter)
image = 'img\pleasewait'
pixmap = QPixmap(resource_path(image+'.png'))
pixmap = pixmap.scaledToHeight(label_img.height(), Qt.SmoothTransformation)
label_img.setPixmap(pixmap)
self.generalLayout.addWidget(label_img, alignment=Qt.AlignCenter)
def setLabelImg(self, bin_color):
image = 'img\'+bin_color'
pixmap = QPixmap(resource_path(image + '.png'))
pixmap = pixmap.scaledToHeight(self.label_img.height(), Qt.SmoothTransformation)
self.label_img.setPixmap(pixmap)
def __init__(self):
super().__init__()
self.setWindowTitle('Bin Collection')
self.setFixedSize(500, 500)
self.setStyleSheet('background-color: #7C7D7B')
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
self.createLabelTop()
self.createLabelImg()
self.createLabelBot()
class BinColCtrl:
def __init__(self, model, view):
self._evaluate = model
self._view = view
self.calculateResult()
def calculateResult(self):
line_top = parseGoodLines(0)
line_bottom = parseGoodLines(1)
self._view.setLabels(line_top, line_bottom)
self._view.
'''
Why the function setLabelImg from class BinColUi is not visible here?
I can call setLabel (as shown above) but no setLabelImg.
'''
def parseGoodLines(linia_number):
global bin_color
try:
if linia_number==0:
start_text='Your next collection is '
else:
start_text='After that: '
kosz_name = good_lines[linia_number][0]
kosz_date = good_lines[linia_number][1]
kosz_date_str = QDate.toString(kosz_date, 'dd MMMM yyyy')
ile_dni=QDate.currentDate().daysTo(kosz_date)
result = '%s%s\nYou need to put it outside before %s\nIt\'s in %s days' \
%(start_text, str.upper(kosz_name), kosz_date_str, str(ile_dni))
except Exception:
result = ERROR_MSG
return result
def resource_path(relative_path):
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
class MakeSoup:
def getDataFromWebsite(self):
URL = 'http://mydurham.durham.gov.uk/article/12690?uprn=100110375827'
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
results = soup.find(id='page_PageContentHolder_template_pnlArticleBody')
return results
def mixSoup(self, dane):
linie_ze_strony = dane.find_all('p')
global good_lines
good_lines=[]
for kosz in linie_ze_strony:
linia_bez_p = str(kosz).replace('<p>', "")
linia_bez_p = str(linia_bez_p).replace('</p>', "")
kosz = linia_bez_p
if 'Your next ' in str(kosz):
if 'rubbish' in str(kosz):
rubbish_len = len(str(kosz)) - 1
date_rubbish = str(kosz)[33:rubbish_len]
if 'recycling' in str(kosz):
recycle_len = len(str(kosz)) - 1
date_recycle = str(kosz)[35:recycle_len]
qdate_rubbish = QDate.fromString(date_rubbish, 'dd MMMM yyyy')
qdate_recycle = QDate.fromString(date_recycle, 'dd MMMM yyyy')
good_lines.append(['Rubbish', qdate_rubbish])
good_lines.append(['Recycling', qdate_recycle])
good_lines.sort(key=itemgetter(1))
return good_lines
def __init__(self):
self.mixSoup(self.getDataFromWebsite())
def main():
bincol = QApplication(sys.argv)
view = BinColUI()
view.show()
MakeSoup()
model = parseGoodLines
BinColCtrl(model=model, view=view)
sys.exit(bincol.exec_())
if __name__ == '__main__':
main()
In class BinColUi I have some functions which I'm using later on to build and change some visual elements. In class BinColCtrl I change text on the labels using function setLabels form BinColUi class and it works alright. But when I try to call function setLabelImg from the same class it's not visible (see attaached pic) and I can't figure why. In fact only function setLabels is available.
Your IDE does not know the type of self._view. It only knows that self._view has a setLabels attribute because you just used that.
Annotate the variable with the correct type and your IDE can discover the method.
class BinColCtrl:
# ``: BinColUI`` tells the IDE the type of ``view`` and ``self._view``
def __init__(self, model, view: BinColUI):
self._evaluate = model
self._view = view
self.calculateResult()
It seems that your IDE doesn't know type of self._view object. It sees setLabels because it was used in the line above.
Try adding type annotation like following:
class BinColCtrl:
def __init__(self, model, view):
self._evaluate = model
self._view: BinColUi = view # <-- this type annotation might help
self.calculateResult()
You can find more about type annotations here

QTextEdit and QPrintPreview works slowly with large HTML table

I'm trying to create reports like MS Access, and thanks to QTextEdit example everything works very nicely. But when I open a large HTML table (about 5000 rows), it takes about 35 seconds to load the table - so it's very slow. How can I optimise the print-preview? Maybe load only one page and change the current page in the print-preview window? But I can't find how to access the print-preview buttons. Or maybe change something with my HTML table?
#!/usr/bin/env python
import sys
from PyQt4 import QtCore, QtGui
class TextEdit(QtGui.QMainWindow):
def __init__(self, fileName=None, parent=None):
super(TextEdit, self).__init__(parent)
self.setupFileActions()
self.textEdit = QtGui.QTextEdit(self)
self.setCentralWidget(self.textEdit)
if fileName is None:
fileName = './test5000.htm'
self.load(fileName)
def load(self, f):
if not QtCore.QFile.exists(f):
return False
fh = QtCore.QFile(f)
if not fh.open(QtCore.QFile.ReadOnly):
return False
data = fh.readAll()
codec = QtCore.QTextCodec.codecForHtml(data)
unistr = codec.toUnicode(data)
if QtCore.Qt.mightBeRichText(unistr):
self.textEdit.setHtml(unistr)
else:
self.textEdit.setPlainText(unistr)
return True
def setupFileActions(self):
menu = QtGui.QMenu("&File", self)
self.menuBar().addMenu(menu)
self.actionOpen = QtGui.QAction(
QtGui.QIcon.fromTheme('document-open'),
"&Open...", self, shortcut=QtGui.QKeySequence.Open,
triggered=self.fileOpen)
menu.addAction(self.actionOpen)
menu.addSeparator()
self.actionPrintPreview = QtGui.QAction(
QtGui.QIcon.fromTheme('fileprint'),
"Print Preview...", self,
shortcut=QtCore.Qt.CTRL + QtCore.Qt.SHIFT + QtCore.Qt.Key_P,
triggered=self.filePrintPreview)
menu.addAction(self.actionPrintPreview)
def fileOpen(self):
fn = QtGui.QFileDialog.getOpenFileName(self, "Open File...", "C:",
"HTML-Files (*.htm *.html);;All Files (*)")
if fn:
self.load(fn)
def filePrintPreview(self):
printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
printer.setOrientation(1)
printer.setPageSize(8)
printer.setPageMargins(20, 20, 20, 20, 0)
printer.setResolution(300)
preview = QtGui.QPrintPreviewDialog(printer, self)
preview.paintRequested.connect(self.printPreview)
preview.exec_()
def printPreview(self, printer):
self.textEdit.print_(printer)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainWindows = []
for fn in sys.argv[1:] or [None]:
textEdit = TextEdit(fn)
textEdit.resize(1024, 768)
textEdit.show()
mainWindows.append(textEdit)
sys.exit(app.exec_())
Sample HTML file with images is here.
When you run script it opens the HTML file (slowly), then menu File->Print preview runs the print-preview dialog.

pyqt4 Segmentation fault (core dumped) when enabling plugins

I'm working on a python web-browser using PyQt4/QtWebKit and I need to enable plugins so it can render flash content.
When I add this line I get a core dump QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True)
My System
Linux rwilson-Aspire-E5-521 3.16.0-47-generic #63~14.04.1-Ubuntu SMP Fri Aug 14 22:56:59 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
PyQt Version
('Qt version:', '4.8.6')
('SIP version:', '4.15.5')
('PyQt version:', '4.10.4')
Here is all the code
#!/usr/bin/env python
from PyQt4 import QtCore, QtGui, QtNetwork, QtWebKit
from PyQt4.QtWebKit import QWebSettings
QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True)
try:
import jquery_rc3
except ImportError:
import jquery_rc2
class MainWindow(QtGui.QMainWindow):
def __init__(self, url):
super(MainWindow, self).__init__()
self.progress = 0
fd = QtCore.QFile(":/jquery.min.js")
if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QFile.Text):
self.jQuery = QtCore.QTextStream(fd).readAll()
fd.close()
else:
self.jQuery = ''
QtNetwork.QNetworkProxyFactory.setUseSystemConfiguration(True)
self.view = QtWebKit.QWebView(self)
self.view.load(url)
self.view.loadFinished.connect(self.adjustLocation)
self.view.titleChanged.connect(self.adjustTitle)
self.view.loadProgress.connect(self.setProgress)
self.view.loadFinished.connect(self.finishLoading)
self.locationEdit = QtGui.QLineEdit(self)
self.locationEdit.setSizePolicy(QtGui.QSizePolicy.Expanding,
self.locationEdit.sizePolicy().verticalPolicy())
self.locationEdit.returnPressed.connect(self.changeLocation)
toolBar = self.addToolBar("Navigation")
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Back))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Forward))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Reload))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Stop))
toolBar.addWidget(self.locationEdit)
viewMenu = self.menuBar().addMenu("&View")
viewSourceAction = QtGui.QAction("Page Source", self)
viewSourceAction.triggered.connect(self.viewSource)
viewMenu.addAction(viewSourceAction)
effectMenu = self.menuBar().addMenu("&Effect")
effectMenu.addAction("Highlight all links", self.highlightAllLinks)
self.rotateAction = QtGui.QAction(
self.style().standardIcon(
QtGui.QStyle.SP_FileDialogDetailedView),
"Turn images upside down", self, checkable=True,
toggled=self.rotateImages)
effectMenu.addAction(self.rotateAction)
toolsMenu = self.menuBar().addMenu("&Tools")
toolsMenu.addAction("Remove GIF images", self.removeGifImages)
toolsMenu.addAction("Remove all inline frames",
self.removeInlineFrames)
toolsMenu.addAction("Remove all object elements",
self.removeObjectElements)
toolsMenu.addAction("Remove all embedded elements",
self.removeEmbeddedElements)
self.setCentralWidget(self.view)
self.setUnifiedTitleAndToolBarOnMac(True)
def viewSource(self):
accessManager = self.view.page().networkAccessManager()
request = QtNetwork.QNetworkRequest(self.view.url())
reply = accessManager.get(request)
reply.finished.connect(self.slotSourceDownloaded)
def slotSourceDownloaded(self):
reply = self.sender()
self.textEdit = QtGui.QTextEdit(None)
self.textEdit.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.textEdit.show()
self.textEdit.setPlainText(QtCore.QTextStream(reply).readAll())
self.textEdit.resize(600, 400)
reply.deleteLater()
def adjustLocation(self):
self.locationEdit.setText(self.view.url().toString())
def changeLocation(self):
url = QtCore.QUrl.fromUserInput(self.locationEdit.text())
self.view.load(url)
self.view.setFocus()
def adjustTitle(self):
if 0 < self.progress < 100:
self.setWindowTitle("%s (%s%%)" % (self.view.title(), self.progress))
else:
self.setWindowTitle(self.view.title())
def setProgress(self, p):
self.progress = p
self.adjustTitle()
def finishLoading(self):
self.progress = 100
self.adjustTitle()
self.view.page().mainFrame().evaluateJavaScript(self.jQuery)
self.rotateImages(self.rotateAction.isChecked())
def highlightAllLinks(self):
code = """$('a').each(
function () {
$(this).css('background-color', 'yellow')
}
)"""
self.view.page().mainFrame().evaluateJavaScript(code)
def rotateImages(self, invert):
if invert:
code = """
$('img').each(
function () {
$(this).css('-webkit-transition', '-webkit-transform 2s');
$(this).css('-webkit-transform', 'rotate(180deg)')
}
)"""
else:
code = """
$('img').each(
function () {
$(this).css('-webkit-transition', '-webkit-transform 2s');
$(this).css('-webkit-transform', 'rotate(0deg)')
}
)"""
self.view.page().mainFrame().evaluateJavaScript(code)
def removeGifImages(self):
code = "$('[src*=gif]').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeInlineFrames(self):
code = "$('iframe').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeObjectElements(self):
code = "$('object').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeEmbeddedElements(self):
code = "$('embed').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
if len(sys.argv) > 1:
url = QtCore.QUrl(sys.argv[1])
else:
url = QtCore.QUrl('http://www.google.com/ncr')
browser = MainWindow(url)
browser.show()
sys.exit(app.exec_())
You need to have an instance of QApplication before using QWebSettings.
Try moving the offending line to MainWindow.__init__.

Encoding error after converting application into executable using py2exe and getting them from mysql (pySide, Python 3)

I have an application that runs perfectly if I run it in directly from Python. However, after I turn it into an executable using py2exe the encoding "breaks".
I run some code that gets the string "Comitê" from a mysql server.
If i run the code:
fromMySql = getFromMysql()
local = "Comitê"
print(fromMySql)
print(local)
And save two files, one running directly from python, the other after compiling with py2exe, i get the following results:
FROM PYTHON:
USING SUBLIME TEXT 3 -> REOPEN WITH ENCODING -> UTF-8:
Comit?
Comit?
USING SUBLIME TEXT 3 -> REOPEN WITH ENCODING -> WESTERN (ISO 8859-1):
Comitê
Comitê
AFTER PY2EXE:
USING SUBLIME TEXT 3 -> REOPEN WITH ENCODING -> UTF-8:
Comit?
Comitê
USING SUBLIME TEXT 3 -> REOPEN WITH ENCODING -> WESTERN (ISO 8859-1):
Comitê
Comitê
It's worth noting that in the beginning of all my files I have:
# -*- coding: utf-8 -*-
The code (removing unimportant bits):
Main window code:
# -*- coding: utf-8 -*-
import sys
import PySide.QtGui as QtGui
from ui.mainWindowComite_ui import Ui_MainWindowComite
import login
import connector as con
class MainWindow(QtGui.QMainWindow, Ui_MainWindowComite):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindowComite.setupUi(self, self)
self.actionCadastro.triggered.connect(self.abrirCadastro)
self.actionDelegacao.triggered.connect(self.abrirDelegacao)
self.actionAcompanhamento.triggered.connect(self.abrirAcompanhamento)
self.actionInvestigacao.triggered.connect(self.abrirInvestigacao)
self.actionHistorico.triggered.connect(self.abrirHistorico)
self.login()
def login(self):
self.loginDialog = login.Login(self)
self.loginDialog.setModal(True)
self.loginDialog.show()
self.loginDialog.rejected.connect(self.close)
self.loginDialog.accepted.connect(self.autenticado)
def autenticado(self):
self.setor = self.loginDialog.setor
print(self.setor)
print("Comitê")
if self.setor != "Comitê":
QtGui.QMessageBox.information(self, u"Erro", u"Esta versão do programa só pode ser utilizada pelo Comitê")
self.close()
def closeEvent(self, event):
con.close()
event.accept()
if __name__ == '__main__':
print("testê")
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
The login class:
import PySide.QtGui as QtGui
import sys
from ui.login_ui import Ui_Login
import connector as con
class Login(QtGui.QDialog, Ui_Login):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_Login.setupUi(self, self)
def accept(self, *args, **kwargs):
self.setor = con.autenticar(self.setorLineEdit.text(),
self.senhaLineEdit.text())
if self.setor is not None: self.setor = self.setor["setor"]
if self.setor is not None:
QtGui.QDialog.accept(self)
else:
QtGui.QMessageBox.information(self, "Falha", "Tente novamente, setor ou senha errada")
The connector class:
# -*- coding: utf-8 -*-
import datetime
import pymysql
def autenticar(login, senha):
query = "Select setor FROM setores " \
"WHERE login='%s' AND senha='%s'" % (login, senha)
execute(query)
setor = cur.fetchall()
return setor[0] if len(setor)>0 else None
def connect():
global cur, con
con = pymysql.connect('localhost', 'root', '', 'database', autocommit=True)
cur = con.cursor(pymysql.cursors.DictCursor)
def execute(query):
try:
cur.execute(query)
except Exception as e:
if str(e)[1:5] == '2013': # Lost connection to server
cur.close()
con.close()
connect()
cur.execute(query)
else:
raise e
def close():
cur.close()
con.close()
connect()

Threading in pyqt4

In my GUI I have to download lots of stuff in between. I use urllib to do that. the problem of course then becomes that the GUI freezes up until everything gets downloaded.
My code is something like following
QtCore.QObject.connect( self.UI.commandLinkButton_2 , QtCore.SIGNAL("clicked()") , self.addStoryToHistory )
wherein the above function has the downloading code.
There is nothing like sending of shared data among this and the process just involves downloading of the data to a location.
What is the simplest way to not freeze up my GUI ? Should i use multiprocessing or QThreads?
Can anybody point me to some links.... I do not wish it to be very complex so if there is any easier way do it please point it out....
Thanks a lot...
Here's an example I've just stripped from a project I was working on a couple of months back using the http example from PyQt as a base. It'll download SIP from the Riverbank website.
It's using QHttp from QtNetwork instead of urllib and the progress bar is connected to its dataReadProgress signal. This should allow you to reliably download a file as well as having a responsive GUI.
from PyQt4.QtCore import QUrl, QFileInfo, QFile, QIODevice
from PyQt4.QtGui import QApplication, QDialog, QProgressBar, QLabel, QPushButton, QDialogButtonBox, \
QVBoxLayout, QMessageBox
from PyQt4.QtNetwork import QHttp
url_to_download = 'http://www.riverbankcomputing.co.uk/static/Downloads/sip4/sip-4.12.3.zip'
class Downloader(QDialog):
def __init__(self, parent=None):
super(Downloader, self).__init__(parent)
self.httpGetId = 0
self.httpRequestAborted = False
self.statusLabel = QLabel('Downloading %s' % url_to_download)
self.closeButton = QPushButton("Close")
self.closeButton.setAutoDefault(False)
self.progressBar = QProgressBar()
buttonBox = QDialogButtonBox()
buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole)
self.http = QHttp(self)
self.http.requestFinished.connect(self.httpRequestFinished)
self.http.dataReadProgress.connect(self.updateDataReadProgress)
self.http.responseHeaderReceived.connect(self.readResponseHeader)
self.closeButton.clicked.connect(self.cancelDownload)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.statusLabel)
mainLayout.addWidget(self.progressBar)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle('Download Example')
self.downloadFile()
def downloadFile(self):
url = QUrl(url_to_download)
fileInfo = QFileInfo(url.path())
fileName = fileInfo.fileName()
if QFile.exists(fileName):
QFile.remove(fileName)
self.outFile = QFile(fileName)
if not self.outFile.open(QIODevice.WriteOnly):
QMessageBox.information(self, 'Error',
'Unable to save the file %s: %s.' % (fileName, self.outFile.errorString()))
self.outFile = None
return
mode = QHttp.ConnectionModeHttp
port = url.port()
if port == -1:
port = 0
self.http.setHost(url.host(), mode, port)
self.httpRequestAborted = False
path = QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:#/")
if path:
path = str(path)
else:
path = '/'
# Download the file.
self.httpGetId = self.http.get(path, self.outFile)
def cancelDownload(self):
self.statusLabel.setText("Download canceled.")
self.httpRequestAborted = True
self.http.abort()
self.close()
def httpRequestFinished(self, requestId, error):
if requestId != self.httpGetId:
return
if self.httpRequestAborted:
if self.outFile is not None:
self.outFile.close()
self.outFile.remove()
self.outFile = None
return
self.outFile.close()
if error:
self.outFile.remove()
QMessageBox.information(self, 'Error',
'Download failed: %s.' % self.http.errorString())
self.statusLabel.setText('Done')
def readResponseHeader(self, responseHeader):
# Check for genuine error conditions.
if responseHeader.statusCode() not in (200, 300, 301, 302, 303, 307):
QMessageBox.information(self, 'Error',
'Download failed: %s.' % responseHeader.reasonPhrase())
self.httpRequestAborted = True
self.http.abort()
def updateDataReadProgress(self, bytesRead, totalBytes):
if self.httpRequestAborted:
return
self.progressBar.setMaximum(totalBytes)
self.progressBar.setValue(bytesRead)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
downloader = Downloader()
downloader.show()
sys.exit(app.exec_())
I suggest you to use the QNetworkManager instead and monitor the download process.
See this other question:
pyQT QNetworkManager and ProgressBars

Categories