I have a code that print something in the console and after some works it clear console and print something new
so putting input() not works for me cause then it will wait user to do something but I want this printing stuff continue
how should I do it?
my code is exctracting a zip file and in the same time printing how much of it is done
import threading
def Ex():
from zipfile import ZipFile
with ZipFile(my zip file) as zf:
zf.extractall(path,pwd=my password)
def loading():
done=False
f=[]
T=time.time()
while not done:
try:
f=os.listdir(my path)
clearConsole = lambda: os.system('cls' if os.name in ('nt', 'dos') else 'clear')
clearConsole()
print('Installing resources : '+str(int(len(f)/25*100))+'%')
except:
pass
if len(f)==25:
done=True
time.sleep(5)
time.sleep(10)
sys.exit()
threading.Thread(target=Ex).start()
threading.Thread(target=loading).start()
If you want to move the cursor to the first of line, use \r.
f = os.listdir("path/to/file")
print('Installing resources : '+str(int(len(f)/25*100))+'%', end='\r')
os.system does not run the commend in the current shell. It opens a new one. So you are just clearing a new shell every 5 seconds. If you really want to hold that, you can use pause command in Windows, which waits for user input and then close it. (cls; pause)
Related
I'm trying to make some project code I have written, more resilient to crashes, except the circumstances of my previous crashes have all been different.
So that I do not have to try and account for every single one, I thought I'd try to get my code to either restart, or execute a copy of itself in place of it and then close itself down gracefully, meaning its replacement, because it's coded identically, would in essence be the same as restarting from the beginning again. The desired result for me would be that while the error resulting circumstances are present, my code would be in a program swap out, or restart loop until such time as it can execute its code normally again....until the next time it faces a similar situation.
To experiment with, I've written two programs. I'm hoping from these examples someone will understand what I am trying to achieve. I want the first script to execute, then start the execute process for the second (in a new terminal) before closing itself down gracefully.
Is this even possible?
Thanks in advance.
first.py
#!/usr/bin/env python
#!/bin/bash
#first.py
import time
import os
import sys
from subprocess import run
import subprocess
thisfile = "first"
#thisfile = "second"
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
#os.system("first.py")
#exec(open("first.py").read())
#run("python "+"first.py", check=False)
#import first
#os.system('python first.py')
#subprocess.call(" python first.py 1", shell=True)
os.execv("first.py", sys.argv)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
#os.system("second.py")
#exec(open("second.py").read())
#run("python "+"second.py", check=False)
#import second
#os.system('python second.py')
#subprocess.call(" python second.py 1", shell=True)
os.execv("second.py", sys.argv)
print("I'm leaving first now")
break
time.sleep(1)
sys.exit("Quitting")
second.py (basically a copy of first.py)
#!/usr/bin/env python
#!/bin/bash
#second.py
import time
import os
import sys
from subprocess import run
import subprocess
#thisfile = "first"
thisfile = "second"
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
#os.system("first.py")
#exec(open("first.py").read())
#run("python "+"first.py", check=False)
#import first
#os.system('python first.py')
#subprocess.call(" python first.py 1", shell=True)
os.execv("first.py", sys.argv)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
#os.system("second.py")
#exec(open("second.py").read())
#run("python "+"second.py", check=False)
#import second
#os.system('python second.py')
#subprocess.call(" python second.py 1", shell=True)
os.execv("second.py", sys.argv)
print("I'm leaving first now")
break
time.sleep(1)
sys.exit("Quitting")
I have tried quite a few solutions as can be seen with my hashed out lines of code. Nothing so far though has given me the result I am after unfortunately.
EDIT: This is the part of the actual code i think i am having problems with. This is the part where I am attempting to publish to my MQTT broker.
try:
client.connect(broker, port, 10) #connect to broker
time.sleep(1)
except:
print("Cannot connect")
sys.exit("Quitting")
Instead of exiting with the "quitting" part, will it keep my code alive if i route it to stay within a repeat loop until such time as it successfully connects to the broker again and then continue back with the rest of the script? Or is this wishful thinking?
You can do this in many ways. Your subprocess.call() option would work - but it depends on the details of implementation. Perhaps the easiest is to use multiprocessing to run the program in a subprocess while the parent simply restarts it as necessary.
import multiprocessing as mp
import time
def do_the_things(arg1, arg2):
print("doing the things")
time.sleep(2) # for test
raise RuntimeError("Virgin Media dun me wrong")
def launch_and_monitor():
while True:
print("start the things")
proc = mp.Process(target=do_the_things, args=(0, 1))
proc.start()
proc.wait()
print("things went awry")
time.sleep(2) # a moment before restart hoping badness resolves
if __name__ == "__main__":
launch_and_monitor()
Note: The child process uses the same terminal as the parent. Running separate terminals is quite a bit more difficult. It would depend, for instance, on how you've setup to have a terminal attach to the pi.
If you want to catch and process errors in the parent process, you could write some extra code to catch the error, pickle it, and have a queue to pass it back to the parent. Multiprocessing pools already do that, so you could just have a pool with 1 process and and a single iterable to consume.
with multiprocessing.Pool(1) as pool:
while True:
try:
result = pool.map(do_the_things, [(0,1)])
except Exception as e:
print("caught", e)
Ok, I got it!
For anyone else interested in trying to do what my original question was:
To close down a script on the occurrence of an error and then open either a new script, or a copy of the original one (for the purpose of having the same functionality as the first) in a new terminal window, this is the answer using my original code samples as an example (first.py and second.py where both scripts run the exact same code - other than defining them as different names and this name allocation defined within for which alternate file to open in its place)
first.py
import time
import subprocess
thisfile = "first"
#thisfile = "second"
if thisfile == "second":
restartcommand = 'python3 /home/mypi/myprograms/first.py'
else:
restartcommand = 'python3 /home/mypi/myprograms/second.py'
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving first now")
break
time.sleep(1)
quit()
second.py
import time
import subprocess
#thisfile = "first"
thisfile = "second"
if thisfile == "second":
restartcommand = 'python3 /home/mypi/myprograms/first.py'
else:
restartcommand = 'python3 /home/mypi/myprograms/second.py'
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving first now")
break
time.sleep(1)
quit()
The result of running either one of these will be that the program runs, then opens the other file and starts running that before closing down itself and this operation will continue back and forth, back and forth until you close down the running file before it gets a chance to open the other file.
Try it! it's fun!
I want to run a program using the subprocess module. While running the program, there are cases where it waits for a button press to continue. It is not waiting for this input to the stdin input. The input sent to stdin is ignored by the program. Only when I press a button on the console will the program continue running.
I tried it like this:
proc = Popen("festival.exe level.sok", stdin=PIPE, text=True)
proc.stdin.write('.')
proc.stdin.flush()
It this case nothing happened.
and like this:
proc = Popen...
proc.communicate('.')
In this case, the python code will not continue running until I press a button on the console. If I set a timeout then the python code continues to run but festival.exe does not continue to run.
What should I do to make festival.exe continue running?
P.S.: festival.exe is a solver for sokoban. This case occurs when the given level cannot be solved. E.g.:
########
#.. $ $#
# # #
########
assuming you have the festival program like this:
from random import getrandbits
solved = getrandbits(1)
if solved:
print("executed correctly")
else:
print('a error ocurred')
input('press a button to continue')
exit(1)
you can solve with:
from subprocess import Popen, PIPE
p = Popen(['python3','festival.py'],stdin=PIPE)
p.communicate(input=b'any\n')
I want to make let's say 5 subprocesses to work in exact same time. Problem is cmd window that appears for a split second so I am unable to see anything. How can I pause it or make anything else to have that window on sight after finished code?
I am opening it with such approach:
client = subprocess.Popen(f'python file.py {arg1} {arg2}', creationflags=CREATE_NEW_CONSOLE)
You could do it by creating Windows batch files that executed your Python script and then pause before ending.
import atexit
import msvcrt
import os
import subprocess
import sys
from tempfile import NamedTemporaryFile
import time
import textwrap
def create_batchfile(proc_no, py_script_filename, *script_args):
"""Create a batch file to execute a Python script and pass it the specified
arguments then pause and wait for a key to be pressed before allowing the
console window to close.
"""
with NamedTemporaryFile('w', delete=False, newline='', suffix='.bat',
) as batchfile:
cmd = (f'"{sys.executable}" "{py_script_filename}" ' +
' '.join(f'"{sarg}"' for sarg in script_args))
print(f'{cmd}') # Display subprocess being executed. (optional)
batchfile.write(textwrap.dedent(f"""\
#echo off
title Subprocess #{proc_no}
{cmd}
echo {py_script_filename} has finished execution
pause
"""))
return batchfile.name
def clean_up(filenames):
"""Remove list of files."""
for filename in filenames:
os.remove(filename)
temp_files = [] # List of files to delete when script finishes.
py_script_filename = 'my_file.py'
atexit.register(clean_up, temp_files)
for i in range(1, 4):
batch_filename = create_batchfile(i, 'my_file.py', i, 'arg 2')
temp_files.append(batch_filename)
subprocess.Popen(batch_filename, creationflags=subprocess.CREATE_NEW_CONSOLE)
print('Press any key to quit: ', end='', flush=True)
while True: # Wait for keypress.
if msvcrt.kbhit():
ch = msvcrt.getch()
if ch in b'\x00\xe0': # Arrow or function key prefix?
ch = msvcrt.getch() # Second call returns the actual key code.
break
time.sleep(0.1)
My project is to make a program that you can run while you are playing games or other programs in the background.
When you press a certain key, your notepad should open and also close after you press the same key again.
I have managed to open notepad with subprocess and that works fine but I have no idea to make it open only when a certain key is pressed.
Thanks for any help!
EDIT:
What I tried already:
import subprocess
import keyboard
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
input()
here it just doesn't detect any keyboard input, the input() at the end makes the program not close instantly
import subprocess
import keyboard
keyboard.add_hotkey('ctrl+k', print,args=("hello", "test"))
input()
Here if I press "ctrl+k it" will print hello test that means the hotkey works fine. When I switch this part "print,args=("hello", "test")" to "subprocess.Popen('C:\Windows\System32\notepad.exe')"(it should open the program instead of printing hello test) the notepad opens instantly after I run the program and when I press "ctrl+k" I get a big error.
A more complex, but still working example could be the following. With this code your program will be always listening the keyboard, not only when you are focused on the input, so may be mre practical in your case
from pynput import keyboard
import subprocess
import threading
class MyException(Exception): pass
class Listening:
"""Is allways waiting for the keyboard input"""
def __init__(self):
self.notepad_open = False # to know the state
with keyboard.Listener(
on_press=self.on_press) as listener:
try:
listener.join()
except:
pass
def on_press(self, key):
try:
if key.char == "k":
if not self.notepad_open:
self.subprocess = \
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
self.notepad_open = True # update state
else:
self.subprocess.kill()
self.notepad_open = False # update state
except: # special key was pressed
pass
thread = threading.Thread(target=lambda: Listening())
thread.start()
The problem is that you check for the key 'k' only once at the beginning. If you want the program to correctly work then you should try this:
import time
import subprocess
import keyboard
while True:
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
time.sleep(5)
-I used the time so that you can only open the program once 5 seconds(If you're curious, see what happens without it)-
Let's say I have a python program that is spitting out lines of text, such as:
while 1:
print "This is a line"
What's the easiest way to allow one to press a key on the keyboard to pause the loop, then to resume if pressed again---but if nothing is pressed it should just continue on automatically?
I'm hoping I don't have to go into something like curses to get this!
You could try this implementation for Linux / Mac (and possible other Unices) (code attribution: found on ActiveState Code Recipes).
On Windows you should check out msvcrt.
import sys, termios, atexit
from select import select
# save the terminal settings
fd = sys.stdin.fileno()
new_term = termios.tcgetattr(fd)
old_term = termios.tcgetattr(fd)
# new terminal setting unbuffered
new_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO)
# switch to normal terminal
def set_normal_term():
termios.tcsetattr(fd, termios.TCSAFLUSH, old_term)
# switch to unbuffered terminal
def set_curses_term():
termios.tcsetattr(fd, termios.TCSAFLUSH, new_term)
def putch(ch):
sys.stdout.write(ch)
def getch():
return sys.stdin.read(1)
def getche():
ch = getch()
putch(ch)
return ch
def kbhit():
dr,dw,de = select([sys.stdin], [], [], 0)
return dr <> []
Implementing what you're looking for would then become something like this:
atexit.register(set_normal_term)
set_curses_term()
while True:
print "myline"
if kbhit():
print "paused..."
ch = getch()
while True
if kbhit():
print "unpaused..."
ch = getch()
break
The easiest way for me, assuming I was working in bash, would be to hit Control-Z to suspend the job, then use the 'fg' command to restore it when I was ready. But since I don't know what platform you're using, I'll have to go with using ChristopheD's solution as your best starting point.
When you press Ctrl+C, a KeyboardInterrupt exception gets raised in your program. You can catch that exception to create the behavior you want - for instance, to pause the program and resume after 5s:
import time
while True:
try:
# This is where you're doing whatever you're doing
print("This is a line")
except KeyboardInterrupt:
print("Paused! Ctrl+C again within 5 seconds to kill program")
# A second KeyboardInterrupt that happens during this sleep will
# not be caught, so it will terminate the program
time.sleep(5)
print("Continuing...")
Or to pause the program indefinitely until the user hits 'enter':
while True:
try:
# This is where you're doing whatever you're doing
print("This is a line")
except KeyboardInterrupt:
print("Interrupted!")
input("Press enter to continue, or Ctrl+C to terminate.")
print("Continuing...")
If you want to catch a second KeyboardInterrupt as well and do something fancy with that, you can do so by nesting try/except blocks, though I wouldn't really recommend that - it's a good idea to allow a string of KeyboardInterrupts to terminate the program.