I want to display a long list interactively in a python command line program.
Basically, think git log, with the scrolling and the q to quit.
How would I do this in python?
The interactive view that git has is called a pager. Git just uses the pager less, or a different one if you configure it.
Basically you need to run less in a subprocess and pipe your output to it.
There are more details on how to do that in this question: Paging output from python
There is also a python helper library: https://pypi.python.org/pypi/pager (I've not used it)
Create a while loop and ask inputs from the prompt.
Eg:
import msvcrt
my_lis = range(1,78)
limit = 25
my_inp = None
while my_lis:
if my_inp != 'q':
print my_lis[:limit]
my_lis = my_lis[limit:]
else:
break
print "Press any key to continue or (q) to Quit :"
my_inp = msvcrt.getch()
# Exit
Related
I have a quite simple problem.
I want to get some console input from a user (without an enter press at the end) and do something with it right away.
I quickly saw that the input() function from python would not work. I thought maybe you could write something like this:
sys.stdout.write("Input: ")
while True:
line = sys.stout.readline()
// Do something with the lines
But unfortunately it does not work because stdout is not readable. With stdin it does not work either because it waits for a enter press of the user.
Is it somehow possible to get lines without the user submit it?
You can get input from console interactively in byte format instead of getting a string with input command.
import sys
while True:
c = sys.stdin.read(1) # Read one byte
Here is what you might be looking for.
To get this working you will need to use pip install keyboard in the command line first.
import keyboard
while True:
key_pressed = keyboard.read_key()
print(f'You pressed {key_pressed}.')
I am trying to learn how to write a script control.py, that runs another script test.py in a loop for a certain number of times, in each run, reads its output and halts it if some predefined output is printed (e.g. the text 'stop now'), and the loop continues its iteration (once test.py has finished, either on its own, or by force). So something along the lines:
for i in range(n):
os.system('test.py someargument')
if output == 'stop now': #stop the current test.py process and continue with next iteration
#output here is supposed to contain what test.py prints
The problem with the above is that, it does not check the output of test.py as it is running, instead it waits until test.py process is finished on its own, right?
Basically trying to learn how I can use a python script to control another one, as it is running. (e.g. having access to what it prints and so on).
Finally, is it possible to run test.py in a new terminal (i.e. not in control.py's terminal) and still achieve the above goals?
An attempt:
test.py is this:
from itertools import permutations
import random as random
perms = [''.join(p) for p in permutations('stop')]
for i in range(1000000):
rand_ind = random.randrange(0,len(perms))
print perms[rand_ind]
And control.py is this: (following Marc's suggestion)
import subprocess
command = ["python", "test.py"]
n = 10
for i in range(n):
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
output = p.stdout.readline().strip()
print output
#if output == '' and p.poll() is not None:
# break
if output == 'stop':
print 'sucess'
p.kill()
break
#Do whatever you want
#rc = p.poll() #Exit Code
You can use subprocess module or also the os.popen
os.popen(command[, mode[, bufsize]])
Open a pipe to or from command. The return value is an open file object connected to the pipe, which can be read or written depending on whether mode is 'r' (default) or 'w'.
With subprocess I would suggest
subprocess.call(['python.exe', command])
or the subprocess.Popen --> that is similar to os.popen (for instance)
With popen you can read the connected object/file and check whether "Stop now" is there.
The os.system is not deprecated and you can use as well (but you won't get a object from that), you can just check if return at the end of execution.
From subprocess.call you can run it in a new terminal or if you want to call multiple times ONLY the test.py --> than you can put your script in a def main() and run the main as much as you want till the "Stop now" is generated.
Hope this solve your query :-) otherwise comment again.
Looking at what you wrote above you can also redirect the output to a file directly from the OS call --> os.system(test.py *args >> /tmp/mickey.txt) then you can check at each round the file.
As said the popen is an object file that you can access.
What you are hinting at in your comment to Marc Cabos' answer is Threading
There are several ways Python can use the functionality of other files. If the content of test.py can be encapsulated in a function or class, then you can import the relevant parts into your program, giving you greater access to the runnings of that code.
As described in other answers you can use the stdout of a script, running it in a subprocess. This could give you separate terminal outputs as you require.
However if you want to run the test.py concurrently and access variables as they are changed then you need to consider threading.
Yes you can use Python to control another program using stdin/stdout, but when using another process output often there is a problem of buffering, in other words the other process doesn't really output anything until it's done.
There are even cases in which the output is buffered or not depending on if the program is started from a terminal or not.
If you are the author of both programs then probably is better using another interprocess channel where the flushing is explicitly controlled by the code, like sockets.
You can use the "subprocess" library for that.
import subprocess
command = ["python", "test.py", "someargument"]
for i in range(n):
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
output = p.stdout.readline()
if output == '' and p.poll() is not None:
break
if output == 'stop now':
#Do whatever you want
rc = p.poll() #Exit Code
I am using pexpect in a python code to run a system command. On running the command, the user may or maynot be prompted with a question. if prompted he must answer y. I want this to happen automatically. I have written the following code -
child = pexpect.spawn( "module load xyz" )
child.expect( "Are you sure you want to clear all loaded modules.*" )
child.sendline( "y" )
My question is what will happen if the system does not prompt the user with the question and the child dies after successful execution of the command?
Thanks
You can wrap your expect statement in a while to continue looping and a try/except to handle the situation where the expected return value is not found. This will allow you to gracefully determine that you have hit the end of the process' output while, at the same time, acting upon the warning message if required.
child = pexpect.spawn( "module load xyz" )
while child.isalive():
try:
child.expect( ""Are you sure you want to clear all loaded modules.*" )
child.sendline( "y" )
except EOF:
pass
To do this, you will need to call from pexpect import EOF.
One more note, though. This will hang unless you either set your buffer to an appropriate size (something I've never gotten the hang of with pexpect) or the string you are expecting is followed by a newline. If neither of these is true, you will hang and have no idea why. In all honesty, I prefer to just do it the hard way and use subprocess.Popen, then read from stdout and stderr and write to stdin.
One more comment. Be careful about using wildcards. They tend to behave in odd ways. Given what you are looking for, you should be able to just drop the asterisk from your expected string.
To run the command and to answer 'y' if the question is asked using pexpect:
#!/usr/bin/env python
import os
import pexpect # $ pip install pexpect
pexpect.run("module load xyz", events={
"Are you sure you want to clear all loaded modules": "y" + os.linesep
})
If you want to use pexpect.spawn directly then the simplified version could look like:
#!/usr/bin/env python
import pexpect # $ pip install pexpect
child = pexpect.spawn("module load xyz")
while True:
i = child.expect(["Are you sure you want to clear all loaded modules",
pexpect.EOF, pexpect.TIMEOUT])
if i == 0:
child.sendline('y')
else: # child exited or the timeout happened
break
I am attempting to run a number of student FORTRAN programs from a python script. These programs are not written in any particular order and often rely on the simple FORTRAN read(*,*) command. A simple program could be:
program main
implicit none
real :: p,t
write(*,*)'Enter p'
read(*,*)p
write(*,*)'Enter t'
read(*,*)t
write(*,*)p,t
end program main
This code pauses and allows the user to enter in certain information based on the prompt. I would like similar feature by using the subprocess Popen command. The script will not know what the inputs are before running, or if they even need to happen.
Currently, for programs with no necessary input the following script works:
p = sub.Popen('./file',stdout=sub.PIPE,stderr=sub.PIPE,stdin=sub.PIPE,shell=True)
output,error = p.communicate()
Is there any way to allow the script runner to enter the data in the terminal as the program is being run?
It looks like you want to use pexpect:
import pexpect
child = pexpect.spawn('student_program')
while child.expect('Enter (\w+)\r\n', pexpect.EOF) == 0:
if child.match[1] == 'p':
child.sendline('3.14159')
To pass interactive control of the program to the user, use child.interact().
So, as the title says, I want a proper code to close my python script.
So far, I've used input('Press Any Key To Exit'), but what that does, is generate a error.
I would like a code that just closes your script without using a error.
Does anyone have a idea? Google gives me the input option, but I don't want that
It closes using this error:
Traceback (most recent call last):
File "C:/Python27/test", line 1, in <module>
input('Press Any Key To Exit')
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
If you are on windows then the cmd pause command should work, although it reads 'press any key to continue'
import os
os.system('pause')
The linux alternative is read, a good description can be found here
This syntax error is caused by using input on Python 2, which will try to eval whatever is typed in at the terminal prompt. If you've pressed enter then Python will essentially try to eval an empty string, eval(""), which causes a SyntaxError instead of the usual NameError.
If you're happy for "any" key to be the enter key, then you can simply swap it out for raw_input instead:
raw_input("Press Enter to continue")
Note that on Python 3 raw_input was renamed to input.
For users finding this question in search, who really want to be able to press any key to exit a prompt and not be restricted to using enter, you may consider to use a 3rd-party library for a cross-platform solution. I recommend the helper library readchar which can be installed with pip install readchar. It works on Linux, macOS, and Windows and on either Python 2 or Python 3.
import readchar
print("Press Any Key To Exit")
k = readchar.readchar()
msvrct - built-in Python module solution (windows)
I would discourage platform specific functions in Python if you can avoid them, but you could use the built-in msvcrt module.
>>> from msvcrt import getch
>>>
>>>
... print("Press any key to continue...")
... _ = getch()
... exit()
A little late to the game, but I wrote a library a couple years ago to do exactly this. It exposes both a pause() function with a customizable message and the more general, cross-platform getch() function inspired by this answer.
Install with pip install py-getch, and use it like this:
from getch import pause
pause()
This prints 'Press any key to continue . . .' by default. Provide a custom message with:
pause('Press Any Key To Exit.')
For convenience, it also comes with a variant that calls sys.exit(status) in a single step:
pause_exit(0, 'Press Any Key To Exit.')
Check it out.
a = input('Press a key to exit')
if a:
exit(0)
Here's a way to end by pressing any key on *nix, without displaying the key and without pressing return. (Credit for the general method goes to Python read a single character from the user.) From poking around SO, it seems like you could use the msvcrt module to duplicate this functionality on Windows, but I don't have it installed anywhere to test. Over-commented to explain what's going on...
import sys, termios, tty
stdinFileDesc = sys.stdin.fileno() #store stdin's file descriptor
oldStdinTtyAttr = termios.tcgetattr(stdinFileDesc) #save stdin's tty attributes so I can reset it later
try:
print 'Press any key to exit...'
tty.setraw(stdinFileDesc) #set the input mode of stdin so that it gets added to char by char rather than line by line
sys.stdin.read(1) #read 1 byte from stdin (indicating that a key has been pressed)
finally:
termios.tcsetattr(stdinFileDesc, termios.TCSADRAIN, oldStdinTtyAttr) #reset stdin to its normal behavior
print 'Goodbye!'
Ok I am on Linux Mint 17.1 "Rebecca" and I seem to have figured it out, As you may know Linux Mint comes with Python installed, you cannot update it nor can you install another version on top of it. I've found out that the python that comes preinstalled in Linux Mint is version 2.7.6, so the following will for sure work on version 2.7.6. If you add raw_input('Press any key to exit') it will not display any error codes but it will tell you that the program exited with code 0. For example this is my first program. MyFirstProgram. Keep in mind it is my first program and I know that it sucks but it is a good example of how to use "Press any key to Exit"
BTW This is also my first post on this website so sorry if I formatted it wrong.
in Windows:
if msvcrt.kbhit():
if msvcrt.getch() == b'q':
exit()
In python 3:
while True:
#runtime..
answer = input("ENTER something to quit: ")
if answer:
break
You can use this code:
from os import system as console
console("#echo off&cls")
#Your main code code
print("Press Any Key To Exit")
console("pause>NUL&exit")