Prior warning: I'm hacking around here out of curiosity. I have no specific reason to do what I'm doing below!
Below is done on Python 2.7.13 on MacOS 10.12.5
I was hacking around with python and I thought it'd be interesting to see what happened if I made stdout nonblocking
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
The call to fcntl is definitely successful. I then try to write a large amount of data (bigger than the max buffer size of a pipe on OSX - which is 65536 bytes). I do it in a variety of ways and get different outcomes, sometimes an exception, sometimes what seems to be a hard fail.
Case 1
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
time.sleep(1)
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
This always throws the exception Caught: [Errno 35] Resource temporarily unavailable. Makes sense I think. Higher level file object wrapper is telling me the write call failed.
Case 2
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
This sometimes throws the exception Caught: [Errno 35] Resource temporarily unavailable or sometimes there is no exception caught and I see the following output:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
Case 3
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
print "Slept"
This sometimes throws the exception Caught: [Errno 35] Resource temporarily unavailable or sometimes there is no exception caught and I just see "Slept". It seems that by printing "Slept" I don't get the error message from Case 2.
Case 4
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
os.write(sys.stdout.fileno(), "A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
Always okay!
Case 5
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
print os.write(sys.stdout.fileno(), "A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
This is sometimes okay or sometimes prints the close failed in file object destructor error message.
My question is, why does this fail like this in python? Am I doing something fundamentally bad here - either with python or at the system level?
It seems like somehow that writing too soon to stdout when the write already failed causes the error message. The error doesn't appear to be an exception. No idea where it's coming from.
N.B. I can write the equivalent program in C and it works okay:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/fcntl.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
const size_t NUM_CHARS = 65537;
char buf[NUM_CHARS];
// Set stdout non-blocking
fcntl(fileno(stdout), F_SETFL, O_NONBLOCK);
// Try to write a large amount of data
memset(buf, 65, NUM_CHARS);
size_t written = fwrite(buf, 1, NUM_CHARS, stdout);
// Wait briefly to give stdout a chance to be read from
usleep(1000);
// This will be written correctly
sprintf(buf, "\nI wrote %zd bytes\n", written);
fwrite(buf, 1, strlen(buf), stdout);
return 0;
}
This is interesting. There are a few things that I've found so far:
Case 1
This is because sys.stdout.write will either write all of the string or throw an exception, which isn't the desired behavior when using O_NONBLOCK. When the underlying call to write returns EAGAIN (Errno 35 on OS X), it should be tried again with the data that is remaining. os.write should be used instead, and the return value should be checked to make sure all the data is written.
This code works as expected:
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
def stdout_write(s):
written = 0
while written < len(s):
try:
written = written + os.write(sys.stdout.fileno(), s[written:])
except OSError as e:
pass
stdout_write("A" * 65537)
Case 2
I suspect that this error message is due to
https://bugs.python.org/issue11380:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
I'm not sure why it's sometimes being called. It may be because there is a print in the except statement which is trying to use the same stdout that a write just failed on.
Case 3
This is similar to Case 1. This code always works for me:
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
def stdout_write(s):
written = 0
while written < len(s):
try:
written = written + os.write(sys.stdout.fileno(), s[written:])
except OSError as e:
pass
stdout_write("A" * 65537)
time.sleep(1)
print "Slept"
Case 4
Make sure you check the return value of os.write, I suspect that the full 65537 bytes are not being successfully written.
Case 5
This is similar to Case 2.
Related
I managed to catch the termination with:
atexit.register(exitHandler)
But how to print out what happened on that point? I want to see if the program aborts due to an error, due to Crtl-C or normal stopping...
It's not the complete solution - but you could wrap code in try except
try:
YOUR CODE HERE
except Exception as e:
print(e)
You should catch KeyboardInterrupt for Ctrl-C. E.g.:
import sys
try:
# your code
except KeyboardInterrupt:
sys.exit('Abort by user interrupt')
except Exception as exc:
sys.exit(f'Abort on error: {exc}')
In the code below, Whenever exception is caught, I would like to exit from the program & print the exception on shell
#stream.py
import hashlib
import sys
import os
import importlib
for line in sys.stdin.readlines():
try:
inpFile = "temp.py"
execfile(inpFile)
line1 = line.strip('\n').split('\t')
print "\t".join(line1)
except:
#exception expected "temp.py:File Not Found", how do I exit the code & print the exception on console ?
sys.exit(1)
Here is the Transform query to call the UDF:
Create table newtable as Select TRANSFORM(id,name) USING
'python stream.py' as (id,name) from mytable;
ideas appreciated.
if you want to catch a specific type of exception (for examle an IOError) you can use
except IOError as e:
and access the error string with e.strerror
if you want to catch all exception you can use sys.exc_info()[0] to access the last error message
for example
try:
1/0
except:
print sys.exc_info()[0]
would print
<type 'exceptions.ZeroDivisionError'>
If you are expecting a specific exception then you should trap that, not everything, which is what you are doing. But there is nothing in your code to generate a "File Not Found" anyway!
EDIT: question code changed! We really do wish to trap "everything". I am using Exception, which traps "almost" everything, see https://docs.python.org/2/library/exceptions.html
This uses Python 2 syntax:
import sys
for line in sys.stdin.readlines():
try:
inpFile = "temp.py"
execfile(inpFile)
line1 = line.strip('\n').split('\t')
print "\t".join(line1)
except Exception as err:
print >> sys.stderr, err # print to stderr (python 2 syntax)
sys.exit(1)
I am trying to print a list of tuples formatted in my stdout. For this, I use the str.format method. Everything works fine, but when I pipe the output to see the
first lines using the head command a IOError occurs.
Here is my code:
# creating the data
data = []$
for i in range(0, 1000):
pid = 'pid%d' % i
uid = 'uid%d' % i
pname = 'pname%d' % i
data.append( (pid, uid, pname) )
# find max leghed string for each field
pids, uids, pnames = zip(*data)
max_pid = len("%s" % max( pids) )
max_uid = len("%s" % max( uids) )
max_pname = len("%s" % max( pnames) )
# my template for the formatted strings
template = "{0:%d}\t{1:%d}\t{2:%d}" % (max_pid, max_uid, max_pname)
# print the formatted output to stdout
for pid, uid, pname in data:
print template.format(pid, uid, pname)
And here is the error I get after running the command: python myscript.py | head
Traceback (most recent call last):
File "lala.py", line 16, in <module>
print template.format(pid, uid, pname)
IOError: [Errno 32] Broken pipe
Can anyone help me on this?
I tried to put print in a try-except block to handle the error,
but after that there was another message in the console:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
I also tried to flush immediately the data through a two consecutive
sys.stdout.write and sys.stdout.flush calls, but nothing happend..
head reads from stdout then closes it. This causes print to fail, internally it writes to sys.stdout, now closed.
You can simply catch the IOError and exit silently:
try:
for pid, uid, pname in data:
print template.format(pid, uid, pname)
except IOError:
# stdout is closed, no point in continuing
# Attempt to close them explicitly to prevent cleanup problems:
try:
sys.stdout.close()
except IOError:
pass
try:
sys.stderr.close()
except IOError:
pass
The behavior you are seeing is linked to the buffered output implementation in Python3. The problem can be avoided using the -u option or setting environmental variable PYTHONUNBUFFERED=x. See the man pages for more information on -u.
$ python2.7 testprint.py | echo
Exc: <type 'exceptions.IOError'>
$ python3.5 testprint.py | echo
Exc: <class 'BrokenPipeError'>
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
$ python3.5 -u testprint.py | echo
Exc: <class 'BrokenPipeError'>
$ export PYTHONUNBUFFERED=x
$ python3.5 testprint.py | echo
Exc: <class 'BrokenPipeError'>
In general, I try to catch the most specific error I can get away with. In this case it is BrokenPipeError:
try:
# I usually call a function here that generates all my output:
for pid, uid, pname in data:
print template.format(pid, uid, pname)
except BrokenPipeError as e:
pass # Ignore. Something like head is truncating output.
finally:
sys.stderr.close()
If this is at the end of execution, I find I only need to close sys.stderr. If I don't close sys.stderr, I'll get a BrokenPipeError but without a stack trace.
This seems to be the minimum fix for writing tools that output to pipelines.
Had this problem with Python3 and debug logging piped into head as well. If your script talks to the network or does file IO, simply dropping IOError's is not a good solution. Despite mentions here, I was not able to catch BrokenPipeError for some reason.
Found a blog post talking about restoring the default signal handler for sigpipe: http://newbebweb.blogspot.com/2012/02/python-head-ioerror-errno-32-broken.html
In short, you add the following to your script before the bulk of the output:
if log.isEnabledFor(logging.DEBUG): # optional
# set default handler to no-op
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
This seems to happen with head, but not other programs such as grep---as mentioned head closes stdout. If you don't use head with the script often, it may not be worth worrying about.
I create a FIFO, and periodically open it in read-only and non-blockingly mode from a.py:
os.mkfifo(cs_cmd_fifo_file, 0777)
io = os.open(fifo, os.O_RDONLY | os.O_NONBLOCK)
buffer = os.read(io, BUFFER_SIZE)
From b.py, open the fifo for writing:
out = open(fifo, 'w')
out.write('sth')
Then a.py will raise an error:
buffer = os.read(io, BUFFER_SIZE)
OSError: [Errno 11] Resource temporarily unavailable
Anyone know what's wrong?
According to the manpage of read(2):
EAGAIN or EWOULDBLOCK
The file descriptor fd refers to a socket and has been marked
nonblocking (O_NONBLOCK), and the read would block.
POSIX.1-2001 allows either error to be returned for this case,
and does not require these constants to have the same value, so
a portable application should check for both possibilities.
So what you're getting is that there is no data available for reading. It is safe to handle the error like this:
try:
buffer = os.read(io, BUFFER_SIZE)
except OSError as err:
if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
buffer = None
else:
raise # something else has happened -- better reraise
if buffer is None:
# nothing was received -- do something else
else:
# buffer contains some received data -- do something with it
Make sure you have the errno module imported: import errno.
out = open(fifo, 'w')
Who will close it for you?
Replace your open+write by this:
with open(fifo, 'w') as fp:
fp.write('sth')
UPD:
Ok, than just make this:
out = os.open(fifo, os.O_NONBLOCK | os.O_WRONLY)
os.write(out, 'tetet')
I have seen several questions about exiting a script after a task is successfully completed, but is there a way to do the same for a script which has failed? I am writing a testing script which just checks that a camera is functioning correctly. If the first test fails it is more than likely that the following tests will also fail; therefore, I want the first failure to invoke an exit and provide output to screen letting me know that there was an error.
I hope this is enough information; let me know if more details are required to help me.
Are you just looking for the exit() function?
import sys
if 1 < 0:
print >> sys.stderr, "Something is seriously wrong."
sys.exit(1)
The (optional) parameter of exit() is the return code the script will return to the shell. Usually values different than 0 signal an error.
You can use sys.exit() to exit. However, if any code higher up catches the SystemExit exception, it won't exit.
You can raise exceptions to identify error conditions. Your top-level code can catch those exceptions and handle them appropriately. You can use sys.exit to exit. E.g., in Python 2.x:
import sys
class CameraInitializationError(StandardError):
pass
def camera_test_1():
pass
def camera_test_2():
raise CameraInitializationError('Failed to initialize camera')
if __name__ == '__main__':
try:
camera_test_1()
camera_test_2()
print 'Camera successfully initialized'
except CameraInitializationError, e:
print >>sys.stderr, 'ERROR: %s' % e
sys.exit(1)
You want to check the return code from the c++ program you are running, and exit if it indicates failure. In the code below, /bin/false and /bin/true are programs that exit with error and success codes, respectively. Replace them with your own program.
import os
import sys
status = os.system('/bin/true')
if status != 0:
# Failure occurred, exit.
print 'true returned error'
sys.exit(1)
status = os.system('/bin/false')
if status != 0:
# Failure occurred, exit.
print 'false returned error'
sys.exit(1)
This assumes that the program you're running exits with zero on success, nonzero on failure.