1

It seems that this question is too long for anyone to comment on... I'm trying to print out some text and a progress bar in a module called 'laulau.py'. Here's a test piece of code that shows a simple version. My goal is to have only one thread, and send information to it. My question is what is the best way to do this ?

file1 (test.py)

#!/usr/bin/env python

from laulau import laulau
import time

print "FIRST WAY"

total=107
t=laulau()
t.echo('this is text')
t.setbartotal(total)
for a in range(1,total):
    t.updatebar(a)
    time.sleep(0.01)
time.sleep(1)
print
print "\ndone loop\n"
t.stop()
time.sleep(1)

print "SECOND WAY"

with laulau().echo("this is text"):
    time.sleep(1)
    print "\nyes this is working\n"
    time.sleep(2)

file2: laulau.py

#!/usr/bin/env python
# vim:fileencoding=utf8

from __future__ import division
import time
import string
import threading
from sys import stdout


class laulau(threading.Thread):

    def __init__(self, arg=None):
        super(laulau,self).__init__()
        self._stop = False
        self.block='█'
        self.empty='□'
        self.TEMPLATE = ('%(progress)s%(empty)s %(percent)3s%%')
        self.progress = None
        self.percent = 0
        self.bar_width=30
        self.bartotal=None

    def run (self):
        # start thread for text
        while not self._stop:
            if self.bartotal is None:
                print self.arg,
                stdout.flush()
                time.sleep(0.3)
            else:
                self.progress = int((self.bar_width * self.percent) / 100)
                self.data = self.TEMPLATE % {
                        'percent': self.percent,
                        'progress': self.block * self.progress,
                        'empty': self.empty * (self.bar_width - self.progress),
                }

                stdout.write('\033[%dG'%1 + self.data + self.arg)
                stdout.flush()
                time.sleep(0.1)

    def setbartotal(self,total):
        # set progress bar total
        if self.bartotal is None:
            self.bartotal = total
            self.updatebar(0)

    def updatebar (self,num):
        self.num=num
        self.percent = self.percentage(self.num)

    def percentage (self,numagain):
        return int((numagain/self.bartotal)*100+1)

    def echo (self,arg="Default"):
        #self.thread_debug()
        self.arg=arg
        self._stop = False
        self.start()
        return self

    def thread_debug(self):
        print "threading enumerate :%s"%threading.enumerate()
        print "current thread :%s"%threading.currentThread()
        print "thread count (including main thread):%s"%threading.activeCount() 

    def stop(self):
        self._stop = True

    def stopped(self):
        return self._stop == True

    def __enter__(self):
        print "\nwe have come through the enter function\n"
        return self

    def __exit__(self, type, value, traceback):
        self._stop = True
        print "\nwe have exited through the exit function\n"
        return isinstance(value, TypeError)

In some cases the second way could work. e.g., when I am printing some text, and just need the thread to die at the end of it, but not in the case of a progress bar when it needs updates sending to it. While this all sort of works, and I learned a lot, I still can't figure out how to encapsulate this class in the way I want. As I only want one thread I don't really need to keep instantiating the class, I just need to do this once.

so e.g. my ideal way would be having three functions only:

  • 1 to control text, turn on progress bar etc (from within one parsed string)
  • 2 to set the progress bar total
  • 3 to set the progress bar iteration

I need to change two variables in the class (for the progress bar)

  • one for the total
  • one for the iteration

...and it works out percentage from that.

First I thought I should start the thread by inheriting the class stuff from threading, then after looking at threading.Thread(target=blah,etc) at first I couldn't see how to use more than one function, then I discovered I could just put the class name in there threading.Thread(target=laulau) and that would start a thread with the class in, but then I was stumped on how to send that thread information seeing as I hadn't assigned it to a 'name' as in t=laulau()

My second thought was to have functions outside of the class in my module, but because I need more than one function I got a bit confused there too by adding this to the beginning of laulau.py:

def eko (arg):
    t=laulau()  
    t.echo(arg)

def barupate(iteration):
    t.updatebar(a)

def bartotal():
    t.setbartotal(a)

the first function made an instance of the class but the preceding functions could not change any variables within that. and then i came across function attributes such as this.

class Foo:
    @webmethod
    def bar(self, arg1, arg2):
         ...

def webmethod(func):
    func.is_webmethod = True
    return func

I then started thinking maybe I could use this somehow but have never come across it before.

Ideally id like something like this:

echo.total(107)
echo('[progressbar] this is text') # starts progress bar and instance of thread if not already there...
for a in range(1,total):
    echo.updatebar(a)
    time.sleep(0.01)
    time.sleep(1)
    echo.stop() # bar would stop at the end of iterations but text animations (blinking etc) may still be going at this point...
    print
    print "\ndone loop\n"

if you know about python you are probably looking at me funny now, but bear in mind that I'm a total beginner non-professional and am learning every day, a lot of it thanks to this site. cheers for any help!

edit: should add that I'm aware of the progress bar module and various other recipes, but I'm making this for learning and fun purposes :)

Community
  • 1
  • 1
funk
  • 1
  • 1
  • 7
  • Do you really need to implement your own progress bar module? In any case, it's worth looking at [`python-progressbar`](http://code.google.com/p/python-progressbar/). – jcollado Dec 13 '11 at 08:40
  • yeah seen that, have to pick it apart a bit... they cant spell 'tipically' :) its not just a progress bar module, it also prints text. i like the way they call it there `pbar =ProgressBar(widgets=widgets) for i in pbar((i for i in range(24))):` – funk Dec 13 '11 at 08:42
  • You're right, this is too long :) but that said, I don't understand why you're using threading to update and display a progress bar? – sarnold Dec 13 '11 at 23:37

1 Answers1

1

If you just need to print out a progress bar, use the sys module, like so:

import sys
import time

progress = "0"                                 #this is an int meant to represent 0-100 percent as 0-100
old = "0"                                      #this represents the last updates progress, so that this update only adds the difference and not the full progress

def updatebar(progress,old):
    for item in range((progress-old)/2)        #this takes the range of progress but divides it by 2, making the progress bar 50 characters long
    sys.stdout.write("-")                      #to change the character used to fill the progress bar change the "-" to something else
    sys.stdout.flush()

#you may not want to use a while loop here, this just has an example of how to use the update function as it adds one to the progress bar every second
while True:
    progress += 1
    updatebar(progress,old)
    old = progress                             #sets the old progress as the current one, because next iteration of the while loop the previous progress will be this one's current progress.
    time.sleep(1)
trevorKirkby
  • 1,886
  • 20
  • 47