0
votes

I have searched and found some answers on redirecting the sys.stdout to a text widget in python, but I can't apply them to my specific needs.

I have coded a simple GUI with tkinter for a downloader found here and I want the stdout messages to appear on a text widget, which after much effort I couldn't achieve.

So let's make my case clearer with my code:

from Tkinter import*
import Tkinter as tk
import tkMessageBox
import urllib2
import sys


#functions
def downloadlinks():

# Configuration BEGIN
    LOGIN = ''
    PASSWORD = ''
    USE_SSL = False
    VERIFY_MD5SUM = False
# Configuration END


    __version__ = '0.1.0'

    import sys
    import os
    import urllib
    import subprocess
    import time
    try:
        import hashlib
        md5 = hashlib.md5
    except ImportError:
        import md5
        md5 = md5.new

    def info(msg):
        sys.stdout.write('\n%s\n\n' % msg)
        sys.stdout.flush()

    def error(msg):
        sys.stderr.write('%s\n' % msg)
        sys.stderr.flush()
        sys.exit(1)

    def transfer_progress(blocks_transfered, block_size, file_size):
        percent = float((blocks_transfered * block_size * 100) / file_size)
        progress = float(blocks_transfered * block_size / 1024)
        downspeed = (float(blocks_transfered * block_size) / float(time.time() - starttime)) / 1024
        sys.stdout.write("Complete: %.0f%% - Downloaded: %.2fKb - Speed: %.3fkb/s\r" % (percent, progress, downspeed))
        sys.stdout.flush()

    def download(source, target):
        global starttime
        starttime = time.time()
        filename, headers = urllib.urlretrieve(source, target, transfer_progress)
        sys.stdout.write('Complete: 100%\n')
        sys.stdout.flush()
        for ss in headers:
            if ss.lower() == "content-disposition":
                filename = headers[ss][headers[ss].find("filename=") + 9:]  # 9 is len("filename=")=9
        urllib.urlcleanup()     # Clear the cache
        return filename

    def verify_file(remote_md5sum, filename):
        f = open(filename, "rb")
        m = md5()
        while True:
            block = f.read(32384)
            if not block:
                break
            m.update(block)
        md5sum = m.hexdigest()
        f.close()
        return md5sum == remote_md5sum

    def main():

        file_link = "https://rapidshare.com/files/33392/examplefile.rar"

        info('Downloading: %s' % file_link.split("/")[5])

        try:
            rapidshare_com, files, fileid, filename = file_link.rsplit('/')[-4:]
        except ValueError:
            error('Invalid Rapidshare link')
        if not rapidshare_com.endswith('rapidshare.com') or files != 'files':
            error('Invalid Rapidshare link')

        if USE_SSL:
            proto = 'https'
            info('SSL is enabled00000000000')

        else:
            proto = 'http'

        if VERIFY_MD5SUM:
            info('MD5 sum verification is enabled')

        info('Downloading: %s' % file_link.split("/")[5])


        if filename.endswith('.html'):
            target_filename = filename[:-5]
        else:
            target_filename = filename
        info('Save file as: %s' % target_filename)


    # API parameters

        params = {
        'sub': 'download_v1',
        'fileid': fileid,
        'filename': filename,
        'try': '1',
        'withmd5hex': '0',
        }

        if VERIFY_MD5SUM:
            params.update({
                'withmd5hex': '1',
                })

        if LOGIN and PASSWORD:
            params.update({
                'login': LOGIN,
                'password': PASSWORD,
                })

        params_string = urllib.urlencode(params)

        api_url = '%s://api.rapidshare.com/cgi-bin/rsapi.cgi' % proto

# Get the first error response
        conn = urllib.urlopen('%s?%s' % (api_url, params_string))
        data = conn.read()
#print data
        conn.close()

# Parse response
        try:
            key, value = data.split(':')
        except ValueError:
            error(data)
        try:
            server, dlauth, countdown, remote_md5sum = value.split(',')
        except ValueError:
            error(data)

# Wait for n seconds (free accounts only)
        if int(countdown):
            for t in range(int(countdown), 0, -1):
                sys.stdout.write('Waiting for %s seconds...\r' % t)
                sys.stdout.flush()
                time.sleep(1)
            info('Waited for %s seconds. Proceeding with file download...' % countdown)

    # API parameters for file download

        dl_params = {
            'sub': 'download_v1',
            'fileid': fileid,
            'filename': filename,
            }

        if LOGIN and PASSWORD:
            dl_params.update({
                'login': LOGIN,
                'password': PASSWORD,
                })
        else:
            dl_params.update({
                'dlauth': dlauth,
                })

        dl_params_string = urllib.urlencode(dl_params)

        download_link = '%s://%s/cgi-bin/rsapi.cgi?%s' % (proto, server, dl_params_string)

        downloaded_filename = download(download_link, target_filename)

        if VERIFY_MD5SUM:
            if remote_md5sum.lower() == 'not found':
                info('Remote MD5 sum is not available. Skipping MD5 sum verification...')
            elif downloaded_filename:
                if verify_file(remote_md5sum.lower(), downloaded_filename):
                    info('Downloaded and verified %s' % downloaded_filename)
                else:
                    error('The downloaded file could not be verified')
            else:
                error('Will not verify. File not found: %s' % downloaded_filename)

        info('Operation Complete')

    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            error('\nAborted')

    tkMessageBox.showinfo('Download Status Notification',"All files have been downloaded.")







#Window Title    
app=Tk()
app.title("Downloader")
app.geometry('700x1080+550+0')
app.resizable(0,0)


#Title    
titleText = StringVar()
titleText.set("Downloader")
label0=Label(app,textvariable=titleText,font=("Times", 16,"bold"),height=2)
label0.pack()

#


f1 = Frame(app, width=600, height=200)
xf1 = Frame(f1, relief=RAISED, borderwidth=5)

#Text
labelText = StringVar()
labelText.set("Enter link:")
label1=Label(f1,textvariable=labelText,font=("Times", 14))
label1.pack(side=LEFT, padx=5,pady=8)


#Field
linkname = StringVar(None)
linkname1 =Entry(f1,textvariable = linkname,font=("Times", 14),justify=CENTER)
linkname1.pack(side=LEFT, padx=5,pady=8)
Label(f1, text='').place(relx=1.06, rely=0.125,anchor=CENTER)
f1.pack()


#Button
downloadbutton=Button(app,text="Download",font=("Times", 12, "bold"),width=20,borderwidth=5,foreground = 'white',background = 'blue',command=downloadlinks)
downloadbutton.pack()

#####
downloadmessages = Text(app,height = 6,width=80,font=("Times", 12),foreground = 'cyan',background='black' )
downloadmessages.insert(END,"")
downloadmessages.pack(padx=20,pady=1)

app.mainloop()

So,let me ask some questions.My code descriptively is like that :

-import modules

-def downloadlinks()

-Window Title

-Title

-Frame with : Text Field

-Button

-Text Widget

When it says my_frame = your_gui_code_here(), does it refer to the Text Widget Code ?

downloadmessages = Text(app,height = 6,width=80,font=("Times", 12),foreground = 'cyan', background='black' )
downloadmessages.insert(END,"")
downloadmessages.pack(padx=20,pady=1)
1
Please post a minimum reproducible example.Daniyal Warraich

1 Answers

2
votes

You would need to open it as a subprocess and then pipe the stdout from there to a writeable source.

e.g.

import subprocess
my_frame = your_gui_code_here()
process = subprocess.Popen('ls', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
my_frame.add_text(process.communicate()[0]) #or however you add text.