2013-05-01 10 views
9

में "अपवाद ... अनदेखा" संदेश का प्रिंटआउट दबाकर पाइथन में एक ज्ञात समस्या है, जहां "close failed in file object destructor" when "Broken pipe" happens on stdout - Python tracker Issue 11380; python - Why does my Python3 script balk at piping its output to head or tail (sys module)? - Stack Overflow में भी देखा गया।पायथन 3

मैं क्या करना चाहता हूं, यह समस्या तब होती है जब यह समस्या होती है, दोनों पायथन 2.7 और पायथन 3+ में। तो मैं एक परीक्षण स्क्रिप्ट, testprint.py इसे चलाने के तैयार करने और (स्निपेट bash में किया दिखाया गया है, उबंटू 11.04):

$ cat > testprint.py <<"EOF" 
import sys 

def main(): 
    teststr = "Hello " * 5 
    sys.stdout.write(teststr + "\n") 

if __name__ == "__main__": 
    main() 
EOF 

$ python2.7 testprint.py 
Hello Hello Hello Hello Hello 

$ python2.7 testprint.py | echo 

close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 

$ python3.2 testprint.py | echo 

Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

ऊपर दिए गए लिंक से उम्मीद थी, वहाँ दो अलग-अलग संदेशों हैं। Help with a piping error (velocityreviews.com) में, sys.stdout.flush() का उपयोग करने के लिए पाइथन 2 को उस संदेश के बजाय IOError पंजीकृत करने के लिए मजबूर करने की अनुशंसा की जाती है; उस के साथ, हमने:

$ cat > testprint.py <<"EOF" 
import sys 

def main(): 
    teststr = "Hello " * 5 
    sys.stdout.write(teststr + "\n") 
    sys.stdout.flush() 

if __name__ == "__main__": 
    main() 
EOF 

$ python2.7 testprint.py | echo 

Traceback (most recent call last): 
    File "testprint.py", line 9, in <module> 
    main() 
    File "testprint.py", line 6, in main 
    sys.stdout.flush() 
IOError: [Errno 32] Broken pipe 

$ python3.2 testprint.py | echo 

Traceback (most recent call last): 
    File "testprint.py", line 9, in <module> 
    main() 
    File "testprint.py", line 6, in main 
    sys.stdout.flush() 
IOError: [Errno 32] Broken pipe 
Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

ठीक है, करीब हो रही ... अब, जिस तरह से "अनदेखा" करने के लिए इन अपवादों (या मेरे मामले में, एक कस्टम त्रुटि संदेश के साथ की जगह), उन्हें संभाल करने के लिए है:

Ignore exceptions - comp.lang.python

> वहाँ बनाने के लिए [दुभाषिया] अपवाद की अनदेखी कोई तरीका है।
नहीं। या तो अपवाद या कोड लिखें जो अपवाद उत्पन्न नहीं करता है।

... और An Introduction to Python - Handling Exceptions नोट्स के रूप में, ऐसा करने का तरीका ब्लॉक को छोड़कर/निकालने का तरीका है। तो चलो कि कोशिश करते हैं:

$ cat > testprint.py <<"EOF" 
import sys 

def main(): 
    teststr = "Hello " * 5 
    try: 
    sys.stdout.write(teststr + "\n") 
    sys.stdout.flush() 
    except IOError: 
    sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n") 

if __name__ == "__main__": 
    main() 
EOF 

$ python2.7 testprint.py | echo 

Exc: <type 'exceptions.IOError'> 

$ python3.2 testprint.py | echo 

Exc: <class 'IOError'> 
Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

ठीक है, तो अजगर 2.7 के लिए काम करता है को छोड़कर कोशिश/यह के रूप में मैं उम्मीद - लेकिन फिर, अजगर 3.2 दोनों हैंडल की उम्मीद, और अभी भी एक Exception ... ignored संदेश उत्पन्न करता है के रूप में! समस्या क्या है - क्या "except IOError" पाइथन 3 के लिए पर्याप्त नहीं है? लेकिन यह होना चाहिए - अन्यथा यह कस्टम "Exc:..." संदेश मुद्रित नहीं होता!

तो - यहां समस्या क्या है, और Exception ... ignored अभी भी पाइथन 3 में क्यों मुद्रित है, भले ही मैं अपवाद को संभालने में सक्षम हूं? और सबसे महत्वपूर्ण बात यह है कि, मैं इसे कैसे संभाल सकता हूं ताकि Exception ... ignored प्रिंट नहीं किया गया है?

+0

यह मेरे लिए सिर, पूंछ, कम, अधिक और अद्वितीय के साथ काम करता है, ऐसा लगता है कि विशेष रूप से गूंज के साथ बातचीत में वास्तविक बग है। "अपवाद अनदेखा" हिस्सा वास्तव में दुभाषिया शट डाउन के दौरान होता है जब यह मानक धाराओं को फिर से फ़्लश करने का प्रयास करता है। – ncoghlan

उत्तर

3

बस इस बारे में कुछ और नोट्स - समस्या अभी भी हल नहीं किया ... पहले:

Issue 6294: Improve shutdown exception ignored message - Python tracker

यह त्रुटि संदेश PyErr_WriteUnraisable, जो __del__ उपाय अपना सकते हैं कई संदर्भों, से कहा जाता है में उत्पन्न होता है । एक __del__ विधि शट डाउन के दौरान बुलाया जाता है, जो आपको त्रुटि के बारे में बता रहा है, लेकिन जहां तक ​​मुझे पता है कि __del__ विधि का कोई तरीका नहीं है पता है कि इसे विशेष रूप से शटडाउन के दौरान बुलाया जा रहा है। तो संदेश को प्रस्तावित फिक्स काम नहीं करेगा। [....]
हालांकि, क्योंकि यह एक संदेश है जिसे आप इसे भी फँस नहीं सकते इसे बदलने के लिए पूरी तरह से सुरक्षित होना चाहिए।

अच्छा, इस संदेश के लिए धन्यवाद कि आप जाल नहीं कर सकते, बहुत सुविधाजनक।मेरा मानना ​​है कि यह किसी भी तरह Ignore exceptions printed to stderr in del() - Stack Overflow से संबंधित है, हालांकि वह पोस्ट (स्पष्ट रूप से) कस्टम __del__ विधियों के बारे में बात करती है।

निम्न संसाधनों का एक सा का उपयोग करना:

... मैं स्क्रिप्ट को संशोधित करके, इसलिए मैं हर संभव संचालकों मैं ओवरलोड, यह देखने के लिए वहाँ कहीं ऐसा स्थान नहीं है जहां मैं इस अपवाद को "संभाल" सकता हूं, इसलिए इसे "अनदेखा" नहीं किया जाता है:

import sys 
import atexit 
import signal 
import inspect, pprint 

def signalPIPE_handler(signal, frame): 
    sys.stderr.write('signalPIPE_handler!'+str(sys.exc_info())+'\n') 
    return #sys.exit(0) # just return doesn't exit! 
signal.signal(signal.SIGPIPE, signalPIPE_handler) 

_old_excepthook = sys.excepthook 
def myexcepthook(exctype, value, intraceback): 
    import sys 
    import traceback 
    sys.stderr.write("myexcepthook\n") 
    if exctype == IOError: 
    sys.stderr.write(" IOError intraceback:\n") 
    traceback.print_tb(intraceback) 
    else: 
    _old_excepthook(exctype, value, intraceback) 
sys.excepthook = myexcepthook 

def _trace(frame, event, arg): 
    if event == 'exception': 
    while frame is not None: 
     filename, lineno = frame.f_code.co_filename, frame.f_lineno 
     sys.stderr.write("_trace exc frame: " + filename \ 
     + " " + str(lineno) + " " + str(frame.f_trace) + str(arg) + "\n") 
     if arg[0] == IOError: 
     myexcepthook(arg[0], arg[1], arg[2]) 
     frame = frame.f_back 
    return _trace 
sys.settrace(_trace) 

def exiter(): 
    import sys 
    sys.stderr.write("Exiting\n") 
atexit.register(exiter) 

def main(): 
    teststr = "Hello " * 5 
    try: 
    sys.stdout.write(teststr + "\n") 
    sys.stdout.flush() 
    except IOError: 
    sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n") 
    #sys.exit(0) 


if __name__ == "__main__": 
    main() 

नोट कैसे इस स्क्रिप्ट चलाता में अंतर:

$ python2.7 testprint.py | echo 

signalPIPE_handler!(None, None, None) 
_trace exc frame: testprint.py 44 <function _trace at 0xb748e5dc>(<type 'exceptions.IOError'>, (32, 'Broken pipe'), <traceback object at 0xb748acac>) 
myexcepthook 
IOError intraceback: 
    File "testprint.py", line 44, in main 
    sys.stdout.flush() 
_trace exc frame: testprint.py 51 None(<type 'exceptions.IOError'>, (32, 'Broken pipe'), <traceback object at 0xb748acac>) 
myexcepthook 
IOError intraceback: 
    File "testprint.py", line 44, in main 
    sys.stdout.flush() 
Exc: <type 'exceptions.IOError'> 
Exiting 

$ python3.2 testprint.py | echo 

signalPIPE_handler!(None, None, None) 
_trace exc frame: testprint.py 44 <function _trace at 0xb74247ac>(<class 'IOError'>, (32, 'Broken pipe'), <traceback object at 0xb747393c>) 
myexcepthook 
IOError intraceback: 
    File "testprint.py", line 44, in main 
    sys.stdout.flush() 
_trace exc frame: testprint.py 51 None(<class 'IOError'>, (32, 'Broken pipe'), <traceback object at 0xb747393c>) 
myexcepthook 
IOError intraceback: 
    File "testprint.py", line 44, in main 
    sys.stdout.flush() 
Exc: <class 'IOError'> 
signalPIPE_handler!(None, None, None) 
Exiting 
signalPIPE_handler!(None, None, None) 
Exception IOError: (32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

ध्यान दें कि signalPIPE_handler दो बार अजगर 3 में और अधिक चलाता है! मुझे लगता है, अगर पाइथन में कुछ प्रकार की "अपवाद कतार" थी, तो मैं इसमें "peek" कर सकता था, और signalPIPE_handler में शेष घटनाओं को हटा सकता था, ताकि Exception ... ignored संदेश दबाने के लिए ... लेकिन मुझे किसी के बारे में पता नहीं है ऐसी चीज़।

अंत में, इन संसाधनों gdb साथ जब डिबग करने के लिए कोशिश कर रहा है अच्छा कर रहे हैं:

... के बाद से मैं python3-dbg की जरूरत नहीं है, यह सब कदम को कम कर देता है मशीन निर्देशों के माध्यम से (layout asmgdb में, फिर Ctrl-X + A), जो वास्तव में मुझे बहुत कुछ नहीं बताता है।

एक टर्मिनल में: लेकिन यहाँ कैसे gdb में समस्या को गति प्रदान करने के लिए है

$ mkfifo foo 
$ gdb python3.2 
... 
Reading symbols from /usr/bin/python3.2...(no debugging symbols found)...done. 
(gdb) run testprint.py > foo 
Starting program: /usr/bin/python3.2 testprint.py > foo 

यहाँ यह अवरुद्ध कर देगा; एक ही diretory में एक और टर्मिनल में कार्य करें:

$ echo <foo 

... तो पहले टर्मिनल पर लौटने - आप देखना चाहिए:

... 
Starting program: /usr/bin/python3.2 testprint.py > foo 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1". 

Program received signal SIGPIPE, Broken pipe. 
0x0012e416 in __kernel_vsyscall() 
(gdb) bt 
#0 0x0012e416 in __kernel_vsyscall() 
#1 0x0013c483 in __write_nocancel() from /lib/i386-linux-gnu/libpthread.so.0 
#2 0x0815b549 in ??() 
#3 0x08170507 in ??() 
#4 0x08175e43 in PyObject_CallMethodObjArgs() 
#5 0x0815df21 in ??() 
#6 0x0815f94e in ??() 
#7 0x0815fb05 in ??() 
#8 0x08170507 in ??() 
#9 0x08175cb1 in _PyObject_CallMethod_SizeT() 
#10 0x08164851 in ??() 
#11 0x080a3a36 in PyEval_EvalFrameEx() 
#12 0x080a3a53 in PyEval_EvalFrameEx() 
#13 0x080a43c8 in PyEval_EvalCodeEx() 
#14 0x080a466f in PyEval_EvalCode() 
#15 0x080c6e9d in PyRun_FileExFlags() 
#16 0x080c70c0 in PyRun_SimpleFileExFlags() 
#17 0x080db537 in Py_Main() 
#18 0x0805deee in main() 
(gdb) finish 
Run till exit from #0 0x0012e416 in __kernel_vsyscall() 
0x0013c483 in __write_nocancel() from /lib/i386-linux-gnu/libpthread.so.0 
... 

दुर्भाग्य से, मैं स्रोत से python3 का निर्माण करने की संभावना नहीं है और अब इसे डीबग करें; इसलिए मैं :)

चीयर्स को किसी ऐसे व्यक्ति के उत्तर की आशा करूंगा जो जानता है!

3

यह त्रुटि संदेश अजगर यह दर्शाता है कि आपूर्ति की पाइप लाइन परिभाषा एक कुछ भ्रामक तरह से टूट गया है, यद्यपि (http://bugs.python.org/issue11380 देखें)

गूंज वास्तव में stdin के माध्यम से इनपुट को स्वीकार नहीं करता है, तो अजगर से इनपुट पाइप समाप्त होता है जल्दी बंद किया जा रहा है। अतिरिक्त अपवाद जो आप देख रहे हैं (अपवाद हैंडलर के बाहर) तब मानक धाराओं को फ्लश करने के निहित प्रयास के कारण है क्योंकि दुभाषिया बंद हो रहा है। यह किसी भी उपयोगकर्ता के पाइथन कोड प्रदान किए गए दायरे के बाहर होता है, इसलिए दुभाषिया सामान्य अपवाद प्रसंस्करण का आह्वान करने के बजाय त्रुटि को stderr पर लिखता है।

यदि आप जानते हैं कि आपको अपने उपयोग के मामले में टूटी हुई पाइप की परवाह नहीं है, तो आप अपने कार्यक्रम के अंत से पहले stdout को स्पष्ट रूप से बंद करके इस मामले से निपट सकते हैं। यह अभी भी टूटी हुई पाइप के बारे में शिकायत होगा, लेकिन यह एक तरह से तुम्हें पकड़ और हमेशा की तरह अपवाद को दबाने देता है कि में कर देगा:

import sys 

def main(): 
    teststr = "Hello " * 5 
    try: 
    sys.stdout.write(teststr + "\n") 
    sys.stdout.flush() 
    except IOError: 
    sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n") 
    try: 
    sys.stdout.close() 
    except IOError: 
    sys.stderr.write("Exc on close: " + str(sys.exc_info()[0]) + "\n") 

if __name__ == "__main__": 
    main() 

इस संस्करण में, केवल उम्मीद उत्पादन में देखा जाता है, क्योंकि भले ही प्रयास बंद करने पर यह के रूप में दुभाषिया शटडाउन के दौरान बंद कर दिया धारा सुनिश्चित करने के लिए पर्याप्त पहले से ही चिह्नित है है:

$ python3 testprint.py | echo 

Exc: <class 'BrokenPipeError'> 
Exc on close: <class 'BrokenPipeError'> 
0

यह एक बहुत बदसूरत हैक मामले stdout के लिए मुद्रण में दिखाया जा रहा से त्रुटि संदेश को दबाने के लिए एक टूटी हुई पाइप के कारण होता है (उदाहरण के लिए क्योंकि आउटपुट के नीचे स्क्रॉल किए बिना your-program.py | less जैसे पेजर प्रक्रिया को छोड़ दिया गया था:

try: 
    actual_code() 
except BrokenPipeError: 
    sys.stdout = os.fdopen(1)