I am creating a commit-msg for .git/hooks/commit-msg and I am getting an EOF Error when asking user for input() on this line
response = input("Are you sure you want to commit? [y/N]: ")
if anyone could help me figure out what is wrong!
Output log
#!/usr/bin/python
import sys
import re
def main():
# open file to read every lines
with open(sys.argv[1], "r") as fp:
lines = fp.readlines()
for idx, line in enumerate(lines):
if line.strip() == "# ------------------------ >8 ------------------------":
break
if line[0] == "#":
continue
# warning message
if (re.search('#[0-9]+$', line) is None):
print("Warning: add issue number related to this commit.")
# ask user to confirm until valid response
try:
while True:
response = input("Are you sure you want to commit? [y/N]: ")
if (response == 'y'):
sys.exit(0)
elif (response == 'N'):
sys.exit(1)
except EOFError as e:
print(e)
# successful commit
print("Success: Perfect commit!")
sys.exit(0)
if __name__ == "__main__":
main()
The commit-msg hook is run with no standard input (more specifically, standard input is redirected from /dev/null), and therefore any attempt to read from standard input will immediately read EOF.
You could try reading from /dev/tty if standard output is a TTY, but be aware that it isn't guaranteed that you'll have one at all. Commits can be run noninteractively without any terminal at all, and the hooks are not designed to be interactive. You'll have to decide what you want to do in that case.
Related
Sorry if I asked this wrong or formatted it wrong, this is my first time here.
Basically, this script is a very, very, simple text editor. The problem is, when it writes to a file, I want it to write:
Hi, my name
is bob.
But, it writes:
is bob.
Hi, my name
How can I fix this?
The code is here:
import time
import os
userdir = os.path.expanduser("~\\Desktop")
usrtxtdir = os.path.expanduser("~\\Desktop\\PythonEdit Output.txt")
def editor():
words = input("\n")
f = open(usrtxtdir,"a")
f.write(words + '\n')
nlq = input('Line saved. "/n" for new line. "/quit" to quit.\n$ ')
if(nlq == '/quit'):
print('Quitting. Your file was saved on your desktop.')
time.sleep(2)
return
elif(nlq == '/n'):
editor()
else:
print("Invalid command.\nBecause Brendan didn't expect for this to happen,\nthe program will quit in six seconds.\nSorry.")
time.sleep(6)
return
def lowlevelinput():
cmd = input("\n$ ")
if(cmd == "/edit"):
editor()
elif(cmd == "/citenote"):
print("Well, also some help from internet tutorials.\nBut Brendan did all the scripting!")
lowlevelinput()
print("Welcome to the PythonEdit Basic Text Editor!\nDeveloped completley by Brendan*!")
print("Type \"/citenote\" to read the citenote on the word Brendan.\nType \"/edit\" to begin editing.")
lowlevelinput()
Nice puzzle. Why are the lines coming out in reverse? Because of output buffering:
When you write to a file, the system doesn't immediately commit your data to disk. This happens periodically (when the buffer is full), or when the file is closed. You never close f, so it is closed for you when f goes out of scope... which happens when the function editor() returns. But editor() calls itself recursively! So the first call to editor() is the last one to exit, and its output is the last to be committed to disk. Neat, eh?
To fix the problem, it is enough to close f as soon as you are done writing:
f = open(usrtxtdir,"a")
f.write(words + '\n')
f.close() # don't forget the parentheses
Or the equivalent:
with open(usrtxtdir, "a") as f:
f.write(words + '\n')
But it's better to fix the organization of your program:
Use a loop to run editor(), not recursive calls.
An editor should be writing out the file at the end of the session, not with every line input. Consider collecting the user input in a list of lines, and writing everything out in one go at the end.
If you do want to write as you go, you should open the file only once, write repeatedly, then close it when done.
You need to close your file after writing, before you try to open it again. Otherwise your writes will not be finalized until the program is closed.
def editor():
words = input("\n")
f = open(usrtxtdir,"a")
f.write(words + '\n')
nlq = input('Line saved. "/n" for new line. "/quit" to quit.\n$ ')
f.close() # your missing line!
if(nlq == '/quit'):
print('Quitting. Your file was saved on your desktop.')
time.sleep(2)
return
elif(nlq == '/n'):
editor()
else:
print("Invalid command.\nBecause Brendan didn't expect for this to happen,\nthe program will quit in six seconds.\nSorry.")
time.sleep(6)
return
If you replace:
f = open(usrtxtdir,"a")
f.write(words + '\n')
with:
with open(usrtxtdir,"a") as f:
f.write(words + '\n')
It comes out in order. Pretty much always use with open() for file access. It handles the closing of the files for you automatically, even in the event of a crash. Although you might consider taking text in memory and writing it only upon quit. But that's not really part of the problem at hand.
Python's file.write() documentation states: "Due to buffering, the string may not actually show up in the file until the flush() or close() method is called"
Since you're recursively reopening the file and writing to it before closing it (or flushing the buffer), the outer value ('Hi, my name') isn't yet written when the inner frame (where you write 'is bob.') completes, which appears to automatically flush the write buffer.
You should be able to add file.flush() to correct it like this:
import time
import os
userdir = os.path.expanduser("~\\Desktop")
usrtxtdir = os.path.expanduser("~\\Desktop\\PythonEdit Output.txt")
def editor():
words = input("\n")
f = open(usrtxtdir,"a")
f.write(words + '\n')
f.flush() # <----- ADD THIS LINE HERE -----< #
nlq = input('Line saved. "/n" for new line. "/quit" to quit.\n$ ')
if(nlq == '/quit'):
print('Quitting. Your file was saved on your desktop.')
time.sleep(2)
return
elif(nlq == '/n'):
editor()
else:
print("Invalid command.\nBecause Brendan didn't expect for this to happen,\nthe program will quit in six seconds.\nSorry.")
time.sleep(6)
return
def lowlevelinput():
cmd = input("\n$ ")
if(cmd == "/edit"):
editor()
elif(cmd == "/citenote"):
print("Well, also some help from internet tutorials.\nBut Brendan did all the scripting!")
lowlevelinput()
print("Welcome to the PythonEdit Basic Text Editor!\nDeveloped completley by Brendan*!")
print("Type \"/citenote\" to read the citenote on the word Brendan.\nType \"/edit\" to begin editing.")
lowlevelinput()
Also, don't forget to close your file after you're done with it!
This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
Closed 6 years ago.
I am brand new to the site and python. I'm learning how to deal with errors using try-except. I'm asking for inputs to open a file and search for a line. This is the program i have now. It mostly works...
try:
file_str = input("Open what file:")
input_file = open(file_str) # potential user error
find_line_str = input("Which line (integer):")
find_line_int = int(find_line_str) # potential user error
line_count_int = 1
for line_str in input_file:
if line_count_int == find_line_int:
print("Line {} of file {} is {}".format(find_line_int, file_str,line_str))
break
line_count_int += 1
else: # get here if line sought doesn't exist
print("Line {} of file {} not found".format(find_line_int,file_str))
input_file.close()
except IOError:
while True:
file_str = input("That file was not found. Please try again:")
except ValueError:
find_line_str = input("Invalid line value. Please try again:")
print("End of the program")
Originally, if there was an error it would say "invalid entry, end of program" Now I am trying to make the program keep asking for inputs until the user gets it right.
With the while loop I put in my except IOError it just loops forever even if I enter a valid file name. If I just ask for input it ends the program after entry.
How do I get it to go back and run the for loop after it receives a valid input? Ive been trying to figure this out for hours I really appreciate the help.
In a nutshell
while True:
try:
#code
break #success case
except IOError:
#error display
#no break, the loop goes on
Updated version of your own script. Added a while loop. The following script will start again from top in case of ValueError or IOError.
while True:
try:
file_str = input("Open what file:")
input_file = open(file_str) # potential user error
find_line_str = input("Which line (integer):")
find_line_int = int(find_line_str) # potential user error
line_count_int = 1
for line_str in input_file:
if line_count_int == find_line_int:
print("Line {} of file {} is {}".format(find_line_int, file_str,line_str))
break
line_count_int += 1
else: # get here if line sought doesn't exist
print("Line {} of file {} not found".format(find_line_int,file_str))
input_file.close()
break
except IOError:
print "That file was not found. Please try again:"
except ValueError:
print "Invalid line value. Please try again:"
print("End of the program")
With the while loop I put in my except IOError it just loops forever even if I enter a valid file name. If I just ask for input it ends the program after entry.
Of course it would:
except IOError:
while True:
file_str = input("That file was not found. Please try again:")
Once the first IOError is occurred there is no way to break from that while loop.
As a rule of thumb, you should keep the least amount of lines in each try block. This way you will have a finer control over what line raised the exception.
In this case, you should try opening the file in a while loop, breaking if succeeding and keep looping if an exception occurred:
while True:
file_str = input("Open what file:")
try:
input_file = open(file_str) # potential user error
break
except IOError:
print('File not found. Try again')
# rest of code
Your try/except(s) should be put in a while-condition loop.
To exit the loop you can then either:
set a condition flag as True before entering the loop and as False as soon as entry is ok - you'll keep looping on any error
or put a 'break' at the end of a correct entry within a 'while True:' loop
In both case, you should accept also quitting the loop on some request from the user (something as a 'cancel' use-case).
I am using python 2.7.6, and when calling raw_input(), there is an exception:
flight_name = raw_input('\nEnter the name of Flight: ')
I found the solution, but why there appears such exception? Is it a bag?
try:
flight_name = raw_input('\nEnter the name of Flight: ')
except (EOFError):
break
You could use:
sys.stdin = open('/dev/tty')
answer = raw_input('Commit anyway? [N/y] ')
source: https://stackoverflow.com/a/7437724/1465640
This answer
sys.stdin = open('/dev/tty')
answer = raw_input('Commit anyway? [N/y] ')
is useful if you've previously read from sys.stdin in your code. In that case, the raw_input line will throw the EOF error without waiting for user input, if you set the sys.stdin = open('/dev/tty') just before raw_input, it resets the stdin and allows the user input to work. (tested in python 2.7) with
## test.py
import sys
for line in sys.stdin:
pass
#sys.stdin = open('/dev/tty')
raw_input("Are you sure?")
echo 'abc' | python test.py
Which raises:
EOFError: EOF when reading a line
Until you uncomment the 2nd to last line.
You're trying to read something from standard input but you're not getting anything, only the EOF. This actually lets you know the user is not providing any input and you can do other things for this condition.
I have pexpect working, but I am having problems printing the output back from it. In my test script below, it creates the ssh connection, and then sends a sudo su -, then my password, and then sends a line that would require sudo access to do (I have also added p.interact() a few times to make sure it is at root). The problem I am having, is with returning the output of the commands I run. In the end I am wanting to run some top commands, and some du -h, and other(much more complex) space commands. But currently when it tries to print p.before, I get:
Traceback (most recent call last):
File "./ssh.py", line 37, in <module>
print p.before()
TypeError: 'str' object is not callable
Here is the script I am working from(edited to remove my pass and such)
#!/usr/bin/env python
import pexpect
import struct, fcntl, os, sys, signal
def sigwinch_passthrough (sig, data):
# Check for buggy platforms (see pexpect.setwinsize()).
if 'TIOCGWINSZ' in dir(termios):
TIOCGWINSZ = termios.TIOCGWINSZ
else:
TIOCGWINSZ = 1074295912 # assume
s = struct.pack ("HHHH", 0, 0, 0, 0)
a = struct.unpack ('HHHH', fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ , s))
global global_pexpect_instance
global_pexpect_instance.setwinsize(a[0],a[1])
ssh_newkey = 'Are you sure you want to continue connecting'
p=pexpect.spawn('ssh user#localhost')
i=p.expect([ssh_newkey,'password:',pexpect.EOF,pexpect.TIMEOUT],1)
if i==0:
print "I say yes"
p.sendline('yes')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==1:
print "I give password",
p.sendline("mypassword")
elif i==2:
print "I either got key or connection timeout"
pass
elif i==3: #timeout
pass
global global_pexpect_instance
global_pexpect_instance = p
p.sendline("sudo su -")
p.sendline("mypasswd")
p.sendline("mkdir /home/user/test")
print p.before
I am working off of this link: http://linux.byexamples.com/archives/346/python-how-to-access-ssh-with-pexpect/
Any help is much appreciated.
EDIT: As Armin Rigo pointed out below. I was calling to p.before as a function like p.before(). Stupid mistake on my part, as this explains why I was getting this error today, and not yesterday when I was trying this. After making that change to my script, and modifying the command being sent, print p.before, and no output is returned. Any other ways to return output from a sendline() command?
Use logfile, that logfile is store all output in terminal.use that example code:-
child = pexpect.spawn("ssh user#localhost")
child.logfile = open("/tmp/mylog", "w")
child.expect(".*assword:")
child.send("guest\r")
child.expect(".*\$ ")
child.sendline("python -V\r")
open the log file and see everything in terminals event
To fetch the complete output after sendline use child.read()
e.g.
cmd_resp = pexpect.spawnu(cmd) # for execution of the command
str_to_search = 'Please Enter The Password'
cmd_resp.sendline('yes') # for sending the input 'yes'
resp = cmd_resp.expect([str_to_search, 'password:', EOF], timeout=30) # fetch the output status
if resp == 1:
cmd_resp.sendline(password)
resp = cmd_resp.expect([str_to_search, 'outputString:', EOF], timeout=30)
print(cmd_resp.read()) # to fetch the complete output log
p.before is a string - not a function. To see the output you have to write
print p.before.
Hope this might help you
I've written code for an assembler, but I am still new to python.
In my code I have the user input a file that will be converted into an assembly language. I think I've almost got it working, but I can't figure out where the user enters the file name.
I'm in (what I think is) IDLE, and then when I hit F5 it runs in the shell. I'm getting an error, but I'm pretty sure it's because no file name has been entered.
Where is the user supposed to input these kinds of things? Is this done from the python shell, or from the command line, do I need to turn it into an executable?
Can someone help clarify where the user is inputting all this information?
I'll put in a segment of code, although I don't think it's necessary to answer my questions, but maybe it'll give you a better idea of my issue.
if __name__ == '__main__':
import sys
if len(sys.argv) == 1:
print 'need filename'
sys.exit(-1)
table = SymbolTable()
parser = Parser(sys.argv[1])
parser.advance()
line = 0
while parser.hasMoreCommands():
if parser.commandType() == 'L_COMMAND':
table.addEntry(parser.symbol(), line)
else:
line += 1
parser.advance()
code = Code()
parser = Parser(sys.argv[1])
parser.advance()
var_stack = 16
while parser.hasMoreCommands():
cmd_type = parser.commandType()
if cmd_type == 'A_COMMAND':
number = 32768
try:
addr = int(parser.symbol())
except:
if table.contains(parser.symbol()):
addr = table.getAddress(parser.symbol())
else:
table.addEntry(parser.symbol(), var_stack)
addr = var_stack
var_stack += 1
bin_number = bin(number | addr)[3:]
assembly = '0' + bin_number
print assembly
elif cmd_type == 'C_COMMAND':
assembly = '111'
assembly += code.comp(parser.comp())
assembly += code.dest(parser.dest())
assembly += code.jump(parser.jump())
print assembly
parser.advance()
The part to note is at the beginning lines 4-6 where it's checking the file name. So once I run my program I get 'need filename' printed to the screen and an error message that looks like this:
Traceback (most recent call last):
File "C:\Python27\Assembler.py", line 98, in <module>
sys.exit(-1)
SystemExit: -1
So where can I input the filename to avoid this error?
The way you have it, Python expects the filename as an argument:
python file.py your_file.asm
If you want to prompt for a filename, use raw_input() (or input() for Python 3):
filename = raw_input('Enter a filename: ') or 'default_file.asm'
sys.argv contains command line arguments.
So, this script has to be run through command-line, for getting input, as said by blender, use raw_input (or input) for getting input from the user, if there are not enough command-line arguments.
Something like this:
if len(sys.argv) == 1:
print "You can also give filename as a command line argument"
filename = raw_input("Enter Filename: ")
else:
filename = sys.argv[1]
And change the line
parser = Parser(sys.argv[1])
To
parser = Parser(filename)