How do you write multiple lines of replaceable console output in python? - python

I am trying to have three different lines of text in the terminal display the different count progresses. The problem is they overwrite each other and honestly I don't know what to do anymore. Any tips or fixes?
def first():
for i in range(50,0,-1):
sys.stdout.write("\rThe current chicken is: {:<3d}".format(i))
time.sleep(1)
def second():
for i in range(100,0,-1):
sys.stdout.write("\rThe current number is: {:<3d}".format(i))
time.sleep(1)
def third():
for i in range(1000,0,-1):
sys.stdout.write("\rThe current cow is: {:<3d}".format(i))
time.sleep(1)
awidj = [first, second, third]
for thread in awidj:
threading.Thread(target=thread).start()

\r will just overwrite the last line that was written. Since you have multiple threads here, there is no way to control which one that is.
For more precise control over console output, check out the curses module.

Related

Why doesn't my piece of code execute in order? [duplicate]

This question already has answers here:
Printing on the same line with time.sleep()
(2 answers)
Closed 3 years ago.
While trying to solve a bigger issue, I reduced my code to two simple commands and I found out that they are not executed in order.
My idea is to give a kind of feedback to the user after clicking on a button(3D Slicer) while running a function. So, what I would expect is to freeze the button immediately after clicking it until the action is finished. So I tried the following to check if the very first command is executed on first position:
def onStartSegmentation(self):
self.segmentButton.setEnabled(False)
sleep(3)
print("2nd step: Starting segmentation")
However, the result is sleeping for 3 seconds and then executing both commands immediately one after the other.
I know this might sound silly, but I can't guess why it's acting like that.
print() function is buffered. That means the output will be buffered before displaying to the screen until the buffer is full or new line character is encountered. If you want to have your output to be displayed on the screen immediately, you need to flush the buffer by using sys.stdout.flush() or you need to explicitly specify it in the argument to print function.
def onStartSegmentation(self):
print("1st step: Starting segmentation", flush = True)
sleep(3)
print("2nd step: Starting segmentation", flush = True)
OR
def onStartSegmentation(self):
print("1st step: Starting segmentation")
sys.stdout.flush()
sleep(3)
print("2nd step: Starting segmentation")
sys.stdout.flush()

Add time delay between every statement of python code

Is there an easy way to execute time delay (like time.sleep(3)) between every statement of Python code without having to explicitly write between every statement?
Like in the below Python Script which performs certain action on SAP GUI window. Sometimes, the script continues to the next statement before the previous statement is complete. So, I had to add a time delay between every statement so that it executes correctly. It is working with time delay, but I end up adding time.sleep(3) between every line. Just wondering if there is a better way?
import win32com.client
import time
sapgui = win32com.client.GetObject("SAPGUI").GetScriptingEngine
session = sapgui.FindById("ses[0]")
def add_record(employee_num, start_date, comp_code):
try:
time.sleep(3)
session.findById("wnd[0]/tbar[0]/okcd").text = "/npa40"
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-PERNR").text = employee_num
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-EINDA").text = start_date
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-WERKS[1,0]").text = comp_code
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSG[2,0]").text = "1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSK[3,0]").text = "U1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT").getAbsoluteRow(0).selected = True
time.sleep(3)
return "Pass"
except:
return "failed"
The right way to do what you asked for is almost certainly to use the debugger, pdb.
The right way to do what you want is probably something completely different: find some signal that tells you that the step is done, and wait for that signal. With problems like this, almost any time you pick will be way, way too long 99% of the time, but still too short 1% of the time. That signal may be joining a thread, or waiting on a (threading or multiprocessing) Condition, or getting from a queue, or awaiting a coroutine or future, or setting the sync flag on an AppleEvent, or… It really depends on what you're doing.
But if you really want to do this, you can use settrace:
def sleeper(frame, event, arg):
if event == 'line':
time.sleep(2)
return sleeper
sys.settrace(sleeper)
One small problem is that the notion of line used by the interpreter may well not be what you want. Briefly, a 'line' trace event is triggered whenever the ceval loop jumps to a different lnotab entry (see lnotab_notes.txt in the source to understand what that means—and you'll probably need at least a passing understanding of how bytecode is interpreted, at least from reading over the dis docs, to understand that). So, for example, a multiline expression is a single line; the line of a with statement may appear twice, etc.1
And there's probably an even bigger problem.
Sometimes, the script continues to next step before the previous step is fully complete.
I don't know what those steps are, but if you put the whole thread to sleep for 2 seconds, there's a good chance the step you're waiting for won't make any progress, because the thread is asleep. (For example, you're not looping through any async or GUI event loops, because you're doing nothing at all.) If so, then after 2 seconds, it'll still be just as incomplete as it was before, and you'll have wasted 2 seconds for nothing.
1. If your notion of "line" is closer to what's described in the reference docs on lexing and parsing Python, you could create an import hook that walks the AST and adds an expression statement with a Call to time.sleep(2) after each list element in each body with a module, definition, or compound statement (and then compiles and execs the result as usual).
Anything you want to happen in a program has to be explicitly stated - this is the nature of programming. This is like asking if you can print hello world without calling print("hello world").
I think the best advice to give you here is: don't think in terms of "lines", but think in term of functions.
use debugging mode and watch each and every line executing line by line.

Python Multithreaded Messenger Simulation. Stuck on timerThread update. What do?

I have a piece of code that simulates a system of messengers (think post office or courier service) delivering letters in a multithreaded way. I want to add a way to manage my messengers "in the field" to increase the efficiency of my system.
tl;dr: How do I update my tens-to-hundreds of timerthreads so they wait longer before calling their function?
Here's what the code I've written so far is supposed to do in steps.
Someone asks for a letter
We check to see if there are any available messengers. If none, we say "oops, sorry. can't help you with that"
If at least one is available, we send the messenger to deliver the letter (new timer thread with its wait param as the time it takes to get there and back)
When the messenger gets back, we put him in the back of the line of available messengers to wait for the next delivery
I do this by removing Messenger objects from a double ended queue, and then adding them back in after a timerthread is done waiting. This is because my Messengers are all unique and eventually I want to track how many deliveries each has had, how far they have traveled, and other stuff.
Here's a pseudoish-codesnippet of the larger program I wrote for this
numMessengers=5
messengerDeque=deque()
pOrder=0.0001
class Messenger:
def __init__(self):
for i in range(numMessengers):
messenger=Messenger()
messengerDeque.append(messenger)
def popDeque():
messenger=idleDeque.popleft()
print 'messenger #?, sent'
return messenger
def appendDeque(messenger):
print 'messenger #?, returned'
messengerDeque.append(messenger)
def randomDelivery():
if numpy.random.randint(0,10000)<=(pOrder*10000):
if len(messengerDeque)!=0:
messenger=popDeque()
tripTime=distance/speed*120
t=threading.Timer(tripTime,appendDeque,args=[messenger])
t.start()
else:
print "oops, sorry. can't help you with that"
The above works in my program.
What I would like to add is some way to 'reroute' my messengers with new orders.
Lets say you have to deliver a letter within an hour of when you get it. You have five messengers and five orders, so they're all busy. You then get a sixth order.
Messenger 2 will be back in 20 minutes, and order six will take 30 minutes to get to the delivery destination. So instead of saying "oops, we can't help you". We would say, ok, Messenger 2, when you get back, immediately go deliver letter six.
With the code I've written, I think this could be done by checking the active threads to see how long until they call their functions, pick the first one you see where that time + how long your new delivery takes is < 1 hr, cancel it, and start a new thread with the time left plus the new time to wait.
I just don't know how to do that.
How do you check how long is left in a timerthread and update it without making a huge mess of your threads?
I'm also open to other, smarter ways of doing what I described.
YAY PYTHON MULTITHREADING!!!!!
Thanks for the help
Using the class threading.Timer wont fulfill your needs. Although there is a "interval" member in Timer instances, once the Timer(thread) started running any changes in interval (time-out) are not considered.
Furthermore you need to know how much time is still left for the timer to be triggered, for which there isn't a method as far as I know.
Furthermore you probably also need a way to identify which Timer instance you need to update with the new timeout value, but this is up-to you.
You should implement your own Timer class, perhaps something along the lines of:
import threading
import time
class MyTimer(threading.Thread):
def __init__(self, timeout, event):
super(MyTimer, self).__init__()
self.to = timeout
self.evt = event
def setTimeout(self, v):
self.end = time.time() + v
def run(self):
self.start = time.time()
self.end = time.time() + self.to
while self.end > time.time():
time.sleep(0) # instead of thread.yield
self.evt()
def getRemaining(self):
return self.end - time.time()
def hi(): print "hi"
T=MyTimer(20,hi)
T.start()
for i in range(10):
time.sleep(1)
# isAlive gives you True if the thread is running
print T.getRemaining(), T.isAlive()
T.setTimeout(1)
for i in range(3):
time.sleep(1)
print T.getRemaining(), T.isAlive()

Non-interfering printing from threads

I am doing some threading with a Python script and it spits out stuff in all kinds of orders. However, I want to print out a single "Remaining: x" at the end of each thread and then erase that line before the next print statement. So basically, I'm trying to implement a progress/status update that erases itself before the next print statement.
I have something like this:
for i in range(1,10):
print "Something here"
print "Remaining: x"
sleep(5)
sys.stdout.write("\033[F")
sys.stdout.write("\033[K")
This works fine when you're printing this out just the way it is; however, as soon as you implement threading, the "Remaining" text doesn't get wiped out all the time and sometimes you get another "Something here" right before it wipes out the previous line.
Just trying to figure out the best way to get my progress/status text organized with multithreading.
Since your code doesn't include any threads it's difficult to give you specific advice about what you are doing wrong.
If it's output sequencing that bothers you, however, you should learn about locking, and have the threads share a lock. The idea would be to grab the lock (so nobody else can), send your output and flush the stream before releasing the lock.
However, the way the code is structured makes this difficult, since there is no way to guarantee that the cursor will always end up at a specific position when you have multiple threads writing output.
As previous commenter mentioned, you can use mutex (RLock) object to serialize access.
import threading
# global lock
stdout_lock = threading.RLock()
def log_stdout(*args):
global stdout_lock
msg = ""
for i in args:
msg += i
with stdout_lock:
sys.stdout.write(msg)
for i in range(1,10):
log_stdout("Something here\n")
log_stdout("Remaining: x\n")
sleep(5)
log_stdout("\033[F")
log_stdout("\033[K")

More efficient text-based loading bar

I am making a program that has a "loading bar" but I can't figure out how to make the code shorter. This might be a simple fix for all I know, but for the life of me, I just can't figure it out. Here is what I have tried to do so far:
def ldbar():
print "Load: 1%"
time.sleep(0.5)
os.system('clear')
print "Load: 2%"
time.sleep(0.5)
os.system('clear')
print "Load: 3%"
time.sleep(0.5)
os.system('clear')
print "Load: 4%"
time.sleep(0.5)
os.system('clear')
print "Load: 5%"
#So on and so forth up to 100%
ldbar()
So, like I said, is there anyway I can make this shorter?
This should work:
def ldbar():
for i in range(1, 100):
print "Load: {}%\r".format(i),
sys.stdout.flush()
time.sleep(0.5)
ldbar()
It uses a for loop to avoid having the same code over and over again. In the print statement I use \r which moves the cursor to the front of the line, allowing it to be overwriten which is why sys.stdout.flush is used to make sure the output is printed without a newline (notice the comma at the end of the print statement which says that a newline should not be printed).
For Python 3 you would use this (but I think you're using python 2):
def ldbar():
for i in range(1, 100):
print("Load: {}%\r".format(i), end="")
sys.stdout.flush()
time.sleep(0.5)
ldbar()
Here's a nice version using a context manager:
from contextlib import contextmanager
import sys
#contextmanager
def scoped_progress_bar(num_steps, message):
class Stepper(object):
'''
Helper class that does the work of actually advancing the progress bar message
'''
def __init__(self, num_steps, message):
self.current_step = 0.0
self.num_steps = num_steps
self.message = message
def step(self, steps = 1.0):
self.current_step += steps
sys.stdout.write('\r{}:{}%'.format(message, (self.current_step/self.num_steps)*100))
sys.stdout.flush()
stepper = Stepper(num_steps, message) # This is where we actually create the progress bar
yield stepper.step # This is where we do the yield secret sauce to let the user step the bar.
# Finally when the context block exits we wind up back here, and advance the bar to 100% if we need to
if stepper.current_step < stepper.num_steps:
stepper.step(stepper.num_steps - stepper.current_step)
The advantage of this method is that
You can specify an arbitrary number of steps
You can step an arbitrary number of steps
Even if you don't hit the end of the number of steps, the context manager will always print 100% at the end
You can specify an arbitrary message
Usage:
with scoped_progress_bar(10, 'loading') as step:
for i in xrange(7):
step()
time.sleep(0.5)
Which prints:
loading: 10%
loading: 20%
...
loading: 70%
loading: 100%
It's likely a bit overkill for your situation, but thought I'd provide it just in case.
An important thing to note with all of these answers is that they assume you won't be printing out stuff during the process in which you're advancing the progress bar. Doing so will still work just fine, it just might not look like what you expect.
First off, use the Progressbar module (https://pypi.python.org/pypi/progressbar), it already does everything you'll ever want from a text-mode progress bar, and then some.
Now for a fix for your specific implementation, what you want to do is write a bar to stdout (or stderr) with no line return, then erase it, then draw it again. You do it like so:
import sys
import time
sys.stdout.write("0%")
# stdout is line-buffered and you didn't print a newline,
# so nothing will show up unless you explicitly call flush.
sys.stdout.flush()
time.sleep(2)
# Move the cursor back to the beginning of the line
# and overwrite the characters.
sys.stdout.write("\r1%")
sys.stdout.flush()
time.sleep(2)
sys.stdout.write("\r2%")
sys.stdout.flush()
# etc.
But really, use progressbar.

Categories

Resources