How to access the GUI output? - python

I'm developing one test bench which runs multiple tests via python gui and prints the output as below.
A Passed
B Passed
C Passed
D Passed
E Passed
Button from gui should be changed to 'Passed' only when A,B,C,D,E all are Passed. If any of these tests fails, it should say failed. What is the way to access this output from gui which is printed on screen.
My code for tests is:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os, time
from PyQt4 import QtGui, QtCore
from progress.bar import Bar
import datetime
import thread
class MyTestBench(QDialog, QtGui.QWidget):
def __init__(self):
super(QDialog, self).__init__()
self.setWindowTitle("Implementation")
self.progressbar = QtGui.QProgressBar()
self.progressbar.setMinimum(0)
self.progressbar.setMaximum(100)
self.run_test_button = QtGui.QPushButton('Run Your Tests')
self.run_test_button.clicked.connect(self.run_test_event)
def run_test_event(self):
thread.start_new_thread(self.run_the_test, ("Thread-1", 0.5))
thread.start_new_thread(self.run_the_progress, ("Thread-2", 0.5))
def run_the_test(self, tname, delay):
os.system("python nxptest.py my_testlist.txt")
self.progressbar.setValue(100)
if self.progressbar.value() == self.progressbar.maximum():
time.sleep(3)
self.run_test_button.setText('Run Your Tests')
def run_the_progress(self, tname, delay):
count = 0
while count < 5:
self.run_test_button.setText('Running.')
time.sleep(0.5)
self.run_test_button.setText('Running..')
time.sleep(0.5)
self.run_test_button.setText('Running...')
value = self.progressbar.value() + 10
self.progressbar.setValue(value)
time.sleep(0.5)
if self.progressbar.value() == self.progressbar.maximum():
self.progressbar.reset()
count = count + 1
app = QApplication(sys.argv)
dialog = MyTestBench()
dialog.setGeometry(100, 100, 200, 50)
dialog.show()
app.exec_()
The main challenge I'm facing here is I'm new to gui programming and I don't know how to access the output that is printed on screen.

If you're trying to get the text output of a program, you can't run that program using os.system. As the docs for that function say:
The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.
If you follow those links, they'll show how to do what you want. But basically, it's something like this:
output = subprocess.check_output(["python", "nxptest.py", "my_testlist.txt"])
If you're using 2.6 or earlier, you won't have check_output; you can read the docs to see how to build it yourself on top of, e.g., communicate, or you can just install the subprocess32 backport from PyPI and use that.
From a comment:
This works but my only concern is there are lot of results for the tests which are printed before it actually prints A Passed B Passed etc.. Im looking for a way to get just this part of string and not the whole output.
That isn't possible. How could your program have any idea which part of the output is "this part of the string" and which part is "a lot of results … which are printed before"?
If you can edit the programs being tested in some way—e.g., make them print their "real" output to stdout, but their "extra" output to stderr, or provide a command-line argument that makes them skip all the extra stuff—that's great. But assuming you can't, there is no alternative but to filter the results.
But this doesn't look very hard. If each line of "real" output is either "X Passed" or "X Failed" and nothing else starts with "X " (where X is any uppercase ASCII letter), that's just:
test_results = {}
for line in output.splitlines():
if line[0] in string.ascii_uppercase and line[1] == ' ':
test_results[line[0]] = line[2:]
Now, at the end, you've got:
{'A': 'Passed', 'B': 'Passed', 'C': 'Passed', 'D': 'Passed', 'E': 'Passed'}
If you want to verify that all of A-E were covered and they all passed:
passed = (set(test_results) == set('ABCDE') and
all(value == 'Passed' for value in test_results.values()))
Of course you could build something nicer that shows which ones were skipped or didn't pass or whatever. But honestly, if you want something more powerful, you should probably be using an existing unit testing framework instead of building one from scratch anyway.

You can mask the printing output through a queue like so:
class FileQ(Queue.Queue):
def __init__(self):
Queue.Queue.__init__(self)
def write(self,data):
self.put(data)
class MyTestBench(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.incoming = FileQ()
self.setWindowTitle("Implementation")
sys.stdout = self.incoming
self.time = QtCore.QTimer()
self.time.timeout.connect(self.refresh)
self.time.start(10)
self.t = QtGui.QTextEdit(self)
self.t.setObjectName('TextOut')
self.box = QtGui.QHBoxLayout(self)
self.setLayout(self.box)
self.box.addWidget(self.t)
self.run_test_event()
self.progressbar = QtGui.QProgressBar(self)
self.progressbar.setObjectName('BarOut')
self.box.addWidget(self.progressbar)
def run_test_event(self):
thread.start_new_thread(self.run_the_test, ("Thread-1", 0.5))
def run_the_test(self,*args):
for i in range(10):
print i
time.sleep(1)
def refresh(self):
try:
data = self.incoming.get_nowait()
except:
return
if data:
self.t.insertPlainText(str(data))
self.progressbar.setValue(int(data)*10)

Related

Why doesn't the value of variable from another module get propagated to other functions even after it's set?

The variable SCRIPT_ENV gets set correctly in main block but that value does not propagate to other functions.
Here's my full working code:
import argparse
import settings
from multiprocessing import Pool
def set_brokers_and_cert_path():
brokers = None
cert_full_path = None
print("I am here man\n\n {0}".format(settings.SCRIPT_ENV))
if settings.SCRIPT_ENV == "some value":
brokers = # use these brokers
cert_full_path = settings.BASE_CERT_PATH + "test_env/"
if settings.SCRIPT_ENV == "some other value":
brokers = # use those brokers
cert_full_path = settings.BASE_CERT_PATH + "new_env/"
return brokers, cert_full_path
def func_b(partition):
kafka_brokers, cert_full_path = set_brokers_and_cert_path()
producer = KafkaProducer(bootstrap_servers=kafka_brokers,
security_protocol='SSL',
ssl_check_hostname=True,
ssl_cafile=cert_full_path +'cacert.pem',
ssl_certfile=cert_full_path + 'certificate.pem',
ssl_keyfile=cert_full_path + 'key.pem',
max_block_ms=1200000,
value_serializer=lambda v: json.dumps(v).encode('utf-8'),
key_serializer=str.encode
)
try:
producer.send(settings.KAFKA_TOPIC,
value="some val",
key="some key",
timestamp_ms=int(time.time()),
headers=[some headers],
partition=partition)
producer.flush()
except AssertionError as e:
print("Error in partition: {0}, {1}".format(partition, e))
def main():
with Pool(settings.NUM_PROCESSES) as p:
p.map(func_b, [i for i in range(0, 24)])
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--env", help="Environment against which the script needs to run")
args = parser.parse_args()
if args.env:
settings.SCRIPT_ENV = args.env
main()
else:
raise Exception("Please pass env argument. Ex: --env test/accept")
In the line "I am here man", it prints None as the value of SCRIPT_ENV.
Here, SCRIPT_ENV gets set perfectly in the if __name__ == "__main__" block, but in func_a, it comes as None.
contents of settings.py:
KAFKA_TOPIC = "some topic"
NUM_PROCESSES = 8
NUM_MESSAGES = 1000
SCRIPT_ENV = None
NUM_PARTITIONS = 24
TEST_BROKERS = [some brokers]
ACCEPT_BROKERS = [some brokers]
BASE_CERT_PATH = "base path"
I run it like this:
python <script.py> --env <value>
In your code example a few references are missing, without which it is not executable. First, we should find out the program parts that lead to the behavior you describe.
I do not suppose the argparse to be crucial. Basically you change an attribute in the module instance settings and call main(), so you can reduce the last part of the program to a few lines:
settings.SCRIPT_ENV = "test"
main()
Function main() propagates function func_b() over multiple processes. Function func_b() itself performs following steps:
Call of function set_brokers_and_cert_path() (you earlier named func_a())
Create an instance of KafkaProducer (producer)
Send some data per producer.
I cannot see that the created instance has any effect on the content of settings.SCRIPT_ENV, so I reduce function func_b() as well and leave only the first function call (for simplicity I take the original name func_a()).
Function func_a() (aka set_brokers_and_cert_path()) likewise has no apparent influence on settings.SCRIPT_ENV, since only a few strings are generated.
For debugging purposes I left the output of the text variables in the function.
All together, I come up with the following executable minimal example, which does not recreate for me the problem you describe (see output).
You can take this example and transfer it piece by piece back to your code and then see which part of the program leads to the problems.
import settings
from multiprocessing import Pool
def func_a():
print("I am here man\n{0}\n".format(settings.SCRIPT_ENV))
def func_b(partition):
func_a()
def main():
with Pool(settings.NUM_PROCESSES) as p:
p.map(func_b, [i for i in range(0, 24)])
settings.SCRIPT_ENV = "Test"
main()
Output
I am here man
Test
I am here man
Test
I am here man
Test
I am here man
Test
...
#RajatBhardwaj, at this point, it is up to you to decide whether you want to participate in finding a solution.
All others who are not interested in a solution would do well not to criticize solutions without having understood its intention.

Pyqt and general python, can this be considered a correct approach for coding?

I have a dialog window containing check-boxes, when each of them is checked a particular class needs to be instantiated and a run a a task on a separated thread (one for each check box). I have 14 check-boxes to check the .isChecked() property and is comprehensible checking the returned Boolean for each of them is not efficient and requires a lot more coding.
Hence I decided to get all the children items corresponding to check-box element, get just those that are checked, appending their names to list and loop through them matching their name to d dictionary which key is the name of the check box and the value is the corresponding class to instantiate.
EXAMPLE:
# class dictionary
self.summary_runnables = {'dupStreetCheckBox': [DupStreetDesc(),0],
'notStreetEsuCheckBox': [StreetsNoEsuDesc(),1],
'notType3CheckBox': [Type3Desc(False),2],
'incFootPathCheckBox': [Type3Desc(True),2],
'dupEsuRefCheckBox': [DupEsuRef(True),3],
'notEsuStreetCheckBox': [NoLinkEsuStreets(),4],
'invCrossRefCheckBox': [InvalidCrossReferences()],
'startEndCheckBox': [CheckStartEnd(tol=10),8],
'tinyEsuCheckBox': [CheckTinyEsus("esu",1)],
'notMaintReinsCheckBox': [CheckMaintReins()],
'asdStartEndCheckBox': [CheckAsdCoords()],
'notMaintPolysCheckBox': [MaintNoPoly(),16],
'notPolysMaintCheckBox': [PolyNoMaint()],
'tinyPolysCheckBox': [CheckTinyEsus("rd_poly",1)]}
# looping through list
self.long_task = QThreadPool(None).globalInstance()
self.long_task.setMaxThreadCount(1)
start_report = StartReport(val_file_path)
end_report = EndReport()
# start_report.setAutoDelete(False)
# end_report.setAutoDelete(False)
end_report.signals.result.connect(self.log_progress)
end_report.signals.finished.connect(self.show_finished)
# end_report.setAutoDelete(False)
start_report.signals.result.connect(self.log_progress)
self.long_task.start(start_report)
# print str(self.check_boxes_names)
for check_box_name in self.check_boxes_names:
run_class = self.summary_runnables[check_box_name]
if run_class[0].__class__.__name__ is 'CheckStartEnd':
run_class[0].tolerance = tolerance
runnable = run_class[0]()
runnable.signals.result.connect(self.log_progress)
self.long_task.start(runnable)
self.long_task.start(end_report)
example of a runnable (even if some of them use different global functions)
I can't post the global functions that write content to file as they are too many and not all 14 tasks execute the same type function. arguments of these functions are int keys to other dictionaries that contain the report static content and the SQL queries to return report main dynamic contents.
class StartReport(QRunnable):
def __init__(self, file_path):
super(StartReport,self).__init__()
# open the db connection in thread
db.open()
self.signals = GeneralSignals()
# self.simple_signal = SimpleSignal()
# print self.signals.result
self.file_path = file_path
self.task = "Starting Report"
self.progress = 1
self.org_name = org_name
self.user = user
self.report_title = "Validation Report"
print "instantiation of start report "
def run(self):
self.signals.result.emit(self.task, self.progress)
if self.file_path is None:
print "I started and found file none "
return
else:
global report_file
# create the file and prints the header
report_file = open(self.file_path, 'wb')
report_file.write(str(self.report_title) + ' for {0} \n'.format(self.org_name))
report_file.write('Created on : {0} at {1} By : {2} \n'.format(datetime.today().strftime("%d/%m/%Y"),
datetime.now().strftime("%H:%M"),
str(self.user)))
report_file.write(
"------------------------------------------------------------------------------------------ \n \n \n \n")
report_file.flush()
os.fsync(report_file.fileno())
class EndReport(QRunnable):
def __init__(self):
super(EndReport,self).__init__()
self.signals = GeneralSignals()
self.task = "Finishing report"
self.progress = 100
def run(self):
self.signals.result.emit(self.task, self.progress)
if report_file is not None:
# write footer and close file
report_file.write("\n \n \n")
report_file.write("---------- End of Report -----------")
report_file.flush()
os.fsync(report_file.fileno())
report_file.close()
self.signals.finished.emit()
# TODO: checking whether opening a db connection in thread might affect the db on the GUI
# if db.isOpen():
# db.close()
else:
return
class DupStreetDesc(QRunnable):
"""
duplicate street description report section creation
:return: void if the report is to text
list[string] if the report is to screen
"""
def __init__(self):
super(DupStreetDesc,self).__init__()
self.signals = GeneralSignals()
self.task = "Checking duplicate street descriptions..."
self.progress = 16.6
def run(self):
self.signals.result.emit(self.task,self.progress)
if report_file is None:
print "report file is none "
# items_list = write_content(0, 0, 0, 0)
# for item in items_list:
# self.signals.list.emit(item)
else:
write_content(0, 0, 0, 0)
Now, I used this approach before and it has always worked fine without using multiprocessing. In this case it works good to some extent, I can run the tasks the first time but if I try to run for the second time I get the following Python Error :
self.long_task.start(run_class[0])
RuntimeError: wrapped C/C++ object of type DupStreetDesc has been deleted
I tried to use run_class[0].setAutoDelete(False) before running them in the loop but pyQt crashes with a minidump error (I am running the code in QGIS) and I the programs exists with few chances to understand what has happened.
On the other hand, if I run my classes separately, checking with an if else statement each check-box, then it works fine, I can run the tasks again and the C++ classes are not deleted, but it isn't a nice coding approach, at least from my very little experience.
Is there anyone else out there who can advise a different approach in order to make this run smoothly without using too many lines of code? Or knows whether there is a more efficient pattern to handle this problem, which I think must be quite common?
It seems that you should create a new instance of each runnable, and allow Qt to automatically delete it. So your dictionary entries could look like this:
'dupStreetCheckBox': [lambda: DupStreetDesc(), 0],
and then you can do:
for check_box_name in self.check_boxes_names:
run_class = self.summary_runnables[check_box_name]
runnable = run_class[0]()
runnable.signals.result.connect(self.log_progress)
self.long_task.start(runnable)
I don't know why setAutoDelete does not work (assuming you are calling it before starting the threadpool). I suppose there might be a bug, but it's impossible to be sure without having a fully-working example to test.

how should I test method that does not return anything?

This is the code from my recent tool I have made, I am trying to write unittest, I have an idea of how to test a method that returns something but don't understand how should i test method that don't like below:
def buildUi(self):
self.label = QtGui.QLabel()
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.setCentralWidget(self.label)
def nextImage(self):
""" switch to next image or previous image
"""
if self._imagesInList:
if self._count == len(self._imagesInList):
self._count = 0
self.showImageByPath(
self._imagesInList[self._count])
if self.animFlag:
self._count += 1
else:
self._count -= 1
def showImageByPath(self, path):
if path:
image = QtGui.QImage(path)
pp = QtGui.QPixmap.fromImage(image)
self.label.setPixmap(pp.scaled(
self.label.size(),
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation))
def playPause(self):
if not self._pause:
self._pause = True
self.updateTimer.start(2500)
return self._pause
else:
self._pause = False
self.updateTimer.stop()
def keyPressEvent(self, keyevent):
""" Capture key to exit, next image, previous image,
on Escape , Key Right and key left respectively.
"""
event = keyevent.key()
if event == QtCore.Qt.Key_Escape:
self.close()
if event == QtCore.Qt.Key_Left:
self.animFlag = False
self.nextImage()
if event == QtCore.Qt.Key_Right:
self.animFlag = True
self.nextImage()
if event == 32:
self._pause = self.playPause()
the complete code for looking can be found here
is it possible to test these methods above or do I have to modify to make them testable ?
Edit: updated:
class TestSlideShow(unittest.TestCase):
""" docstring for TestSlideShow
"""
def setUp(self):
self.mox = mox.Mox()
self.imgLst = ['/folder/test/images/test1.jpg', '/folder/test/images/test2.JPG',
'/folder/test/images/test3.png', '/folder/test/images/test4.PNG']
app = QtGui.QApplication([])
self.show = slideShow.SlideShowPics(imgLst=self.imgLst, ui=False)
def tearDown(self):
self.mox.UnsetStubs()
self.mox.ResetAll()
def test_nextImage(self):
self.mox.StubOutWithMock(self.show, 'prepairWindow')
self.show.prepairWindow()
self.mox.StubOutWithMock(self.show, 'showImageByPath')
self.show.showImageByPath(self.imgLst[1])
self.show.nextImage()
# self.mox.ReplayAll()
self.assertEquals(1, self.show.count)
self.assertEquals(self.imgLst[1], self.show._imagesInList[1])
# self.mox.VerifyAll()
def test_nextImage_animFlag_False(self):
self.show.animFlag = False
self.show.count = 4
self.mox.StubOutWithMock(self.show, 'prepairWindow')
self.show.prepairWindow()
self.mox.StubOutWithMock(self.show, 'showImageByPath')
self.show.showImageByPath(self.imgLst[3])
print self.show.count
self.show.nextImage()
print self.show.count
# self.assertEquals(3, self.show.count)
self.assertEquals(self.imgLst[3], self.show._imagesInList[3])
if __name__ == '__main__':
unittest.main()
the first test when self.show.animFlag is True works fine and but the when I manually set the animFlag= False then second test fails.
This is the problem with writing unittest after the code - you then realize your code is difficult to test. Writing the tests before the code (well, really "along" the code - you don't write all tests before start coding, but still you dont write a line of code before you have a test for it) makes sure you don't have such a problem.
Now even with the "test first" approach you do have to test methods that don't return anything. The way to do so is to test for the expected side effects. Some of these side effects are easy to test - in your above case, you can test the value of self._count before and after the call to nextImage, depending on your object's state (_imagesInList and animFlag mostly). Where it gets more difficult is if you want to test that nextImage does actually call showImageByPath with the correct arguments, and with your current design the only way to do so is to monkeypatch showImageByPath for the tests. Testing showImageByPath will require patching / mocking self.label.setPixmap(), etc.
As others already pointed there are a couple mock/stub libs that can help, but they won't solve all possible testability issues and you may have to rethink your design to make things easier - like not hardcoding the call to QtGui.QLabel() in buildUI() but have some way to "inject" the desired componant (QtGui.QLabel() or a mock) instead. As a general rule, testable code has very few hard-coded dependencies, few side effects, and lot of small classes with short methods (instead of huge classes with long methods).

Running system commands in Python using curses and panel, and come back to previous menu

I'm coding a python script using several commanline tools like top, so i need a proper visual feedback. Now it is time to give it a menu, so here comes the problem.
I found here a great approach of what i need, but every try to display a feedback before come back to previous menu is futile.
I just need menus, submenus, launch commands, terminate it, and back to previous menu. a GREAT bonus would be to run them in a split of the term.
Is there any pattern/skeleton/stuff/whatever to use as template in order to display several kind of widget with a predictable output?
here is a example of code,which two examples of functions to run:
#!/usr/bin/env python2
import curses
from curses import panel
class Menu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(0,0)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
self.items.append(('exit','exit'))
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items)-1
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
self.window.refresh()
curses.doupdate()
for index, item in enumerate(self.items):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = '%d. %s' % (index, item[0])
self.window.addstr(1+index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord('\n')]:
if self.position == len(self.items)-1:
break
else:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
######################################################### !#
######################################################### !#
############# HERE MY FUNCTIONS examples
############ Everithing works OK, but displays it awfully
def GetPid(name):
import subprocess
command= str(("""pgrep %s""") % name )
p = subprocess.Popen(command, shell = True, stdout = subprocess.PIPE)
procs = []
salida = p.stdout
for line in salida:
procs.append(str.strip(line))
return procs
def top():
os.system("top")
def menuGP():
print GetPid("top")
######################################################### !#
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
curses.curs_set(0)
submenu_items = [
('beep', curses.beep),
('top', top)
]
submenu = Menu(submenu_items, self.screen)
main_menu_items = [
('get PID', GetPid),
('submenu', submenu.display)
]
main_menu = Menu(main_menu_items, self.screen)
main_menu.display()
if __name__ == '__main__':
curses.wrapper(MyApp)
Thanks in advise (and sorry for my rough english)
You really have two choices. One you can leave curses mode, execute your program, then resume curses. Two, you can execute your program asynchronously, parse its output and write it to the screen.
The good news on the first option is that you don't actually need to write any fancy save_state / load_state methods for the ui. Curses does this for you. Here's a simple example to show my point
import curses, time, subprocess
class suspend_curses():
"""Context Manager to temporarily leave curses mode"""
def __enter__(self):
curses.endwin()
def __exit__(self, exc_type, exc_val, tb):
newscr = curses.initscr()
newscr.addstr('Newscreen is %s\n' % newscr)
newscr.refresh()
curses.doupdate()
def main(stdscr):
stdscr.addstr('Stdscreen is %s\n' % stdscr)
stdscr.refresh()
time.sleep(1)
with suspend_curses():
subprocess.call(['ls'])
time.sleep(1)
stdscr.refresh()
time.sleep(5)
curses.wrapper(main)
If you run the example, you will notice that the screen created by curses.wrapper and the one created in curses.initscr when resuming are the same object. That is, the window returned by curses.initscr is a singleton. This lets us exit curses and resume like above without having to update each widget's self.screen references each time.
The second option is much more involved but also much more flexible. The following is just to represent the basic idea.
class procWidget():
def __init__(self, stdscr):
# make subwindow / panel
self.proc = subprocess.Popen(my_args, stdout=subprocess.PIPE)
def update(self):
data = self.proc.stdout.readline()
# parse data as necessary
# call addstr() and refresh()
Then somewhere in your program you will want to call update on all your procWidgets on a timer. This gives you the option of making your subwindow any size/place so you can have as many procWidgets as will fit. You will have to add some handling for when the process terminates and other similar events of course.

beginners program designed using threads and classes

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 :)
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)

Categories

Resources