2012-06-21 25 views
18

मेरे पास एक पाइथन स्क्रिप्ट है जो मेरे नियोक्ता द्वारा प्रदान किए गए कुछ बंद-बॉक्स पायथन कार्यों का उपयोग कर रही है (यानी मैं इन कार्यों को संपादित नहीं कर सकता)। जब मैं इन कार्यों को कॉल करता हूं, तो वे मेरे लिनक्स टर्मिनल पर आउटपुट प्रिंट कर रहे हैं जिन्हें मैं दबाना चाहता हूं। मैंने stdout/stderr के माध्यम से पुनर्निर्देशित करने का प्रयास किया है;पायथन कार्यों से stdout/stderr प्रिंट को दबाएं

orig_out = sys.stdout 
sys.stdout = StringIO() 
rogue_function() 
sys.stdout = orig_out 

लेकिन यह आउटपुट को पकड़ने में विफल रहता है। मुझे लगता है कि मैं जिन कार्यों के माध्यम से कॉल कर रहा हूं- पाइथन (ऊपर से rogue_function()) वास्तव में संकलित सी-कोड के लिए रैपर हैं, जो वास्तव में प्रिंटिंग कर रहे हैं।

क्या किसी को इस तरह से पता है कि मैं किसी फ़ंक्शन द्वारा stdout/stderr को किसी भी प्रिंट को "गहरा कैप्चर" कर सकता हूं (और किसी भी उप-फ़ंक्शंस जो कॉल करता है)?

अद्यतन:

:

# Define a context manager to suppress stdout and stderr. 
class suppress_stdout_stderr(object): 
    ''' 
    A context manager for doing a "deep suppression" of stdout and stderr in 
    Python, i.e. will suppress all print, even if the print originates in a 
    compiled C/Fortran sub-function. 
     This will not suppress raised exceptions, since exceptions are printed 
    to stderr just before a script exits, and after the context manager has 
    exited (at least, I think that is why it lets exceptions through).  

    ''' 
    def __init__(self): 
     # Open a pair of null files 
     self.null_fds = [os.open(os.devnull,os.O_RDWR) for x in range(2)] 
     # Save the actual stdout (1) and stderr (2) file descriptors. 
     self.save_fds = [os.dup(1), os.dup(2)] 

    def __enter__(self): 
     # Assign the null pointers to stdout and stderr. 
     os.dup2(self.null_fds[0],1) 
     os.dup2(self.null_fds[1],2) 

    def __exit__(self, *_): 
     # Re-assign the real stdout/stderr back to (1) and (2) 
     os.dup2(self.save_fds[0],1) 
     os.dup2(self.save_fds[1],2) 
     # Close all file descriptors 
     for fd in self.null_fds + self.save_fds: 
      os.close(fd) 

इस तुम सिर्फ का उपयोग करें:

मैं विधि नीचे चयनित जवाब में उल्लिखित ले रहे हैं और एक संदर्भ प्रबंधक लेखन stdout और stderr को दबाने के लिए समाप्त हो गया

with suppress_stdout_stderr(): 
    rogue_function() 

यह "बहुत अच्छा" काम करता है। यह प्रिंट स्क्रिप्ट को उन दुष्ट कार्यों से दबाता है जो मेरी लिपि को छेड़छाड़ कर रहे थे। मैंने परीक्षण में देखा कि यह उठाए गए अपवादों के साथ-साथ कुछ लॉगर प्रिंट के माध्यम से भी देता है, और मैं पूरी तरह स्पष्ट क्यों नहीं हूं। मुझे लगता है कि के साथ ऐसा कुछ करने के लिए है जब ये संदेश stdout/stderr को भेजे जाते हैं (मुझे लगता है कि यह मेरे संदर्भ प्रबंधक से बाहर निकलने के बाद होता है)। किसी को भी इस बात की पुष्टि कर सकते हैं, मैं विवरण सुनने में रुचि रखते आप एक linux आधारित मशीन पर इस स्क्रिप्ट चला रहे हैं हो जाएगा ...

+1

करता है [इस दृष्टिकोण] (http://stackoverflow.com/a/978264/344821) में के रूप में चयन करने के लिए (अनुमति देता है संबंधित साइडबार) काम करते हैं? – Dougal

+0

'sys.stdout' को 'स्ट्रिंगियो()' में सेट करने के बजाय, क्या आपने इसे फ़ाइल में सेट करने का प्रयास किया है? यानी 'sys.stdout = open (' log.txt ',' w ') ' – carmenism

+0

डगल, धन्यवाद, यह आशाजनक लग रहा है, मैं कल इसे आजमाउंगा। nullpointer, मैंने इसे एक कस्टम NullPointer() कक्षा में निर्देशित करने की कोशिश की, और यह भी काम नहीं किया। – jeremiahbuddha

उत्तर

5

This approach (संबंधित साइडबार के माध्यम से मिला) काम कर सकता है। यह sys.stdout, आदि में केवल रैपरों की बजाय फ़ाइल डिस्क्रिप्टरों को फिर से सौंपता है।

-2

, तो आप में सक्षम होना चाहिए करने के लिए:

$> ./runscript.py > output.txt 
+0

मैं स्क्रिप्ट द्वारा उत्पन्न सभी आउटपुट को दबाना नहीं चाहता, केवल इन विशेष कार्यों द्वारा उत्पन्न नकली आउटपुट। अन्यथा, हाँ, यह सबसे आसान समाधान होगा ... – jeremiahbuddha

+0

क्या यह मदद करेगा: उन विशेष कार्यों से पहले और बाद में एक प्रिंट जोड़ें। – GeneralBecos

1

आप की कोशिश की stderr भी पुनर्निर्देशित करने के लिए? उदा।

sys.stdout = StringIO(); 
sys.stderr = StringIO(); 
foo(bar); 
sys.stdout = sys.__stdout__; # These are provided by python 
sys.stderr = sys.__stderr__; 

स्ट्रिंगियो का उपयोग करके अतिरिक्त मेमोरी का उपयोग भी हो सकता है। आप इसके बजाय एक डमी डिवाइस का उपयोग कर सकते हैं (उदा। http://coreygoldberg.blogspot.com/2009/05/python-redirect-or-turn-off-stdout-and.html)।

+0

से ऊपर जोड़े गए प्रिंटों के बीच सबकुछ से छुटकारा पाने के लिए एक रेगेक्स के साथ आउटपुट को पार्स करें हाँ, मैंने स्टडआउट और स्टेडर, दोनों पासा दोनों की कोशिश की ... – jeremiahbuddha

+0

यह हो सकता है कि सी कोड सीधे stdout पर लिख रहा हो; आप शायद इसे पुनर्निर्देशित करने में सक्षम नहीं होंगे। माफ़ कीजिये। – Bob

1

मेरा समाधान आपके जैसा ही है लेकिन contextlib का उपयोग करता है और यह समझने के लिए थोड़ा छोटा और आसान है (IMHO)।

import contextlib 


@contextlib.contextmanager 
def stdchannel_redirected(stdchannel, dest_filename): 
    """ 
    A context manager to temporarily redirect stdout or stderr 

    e.g.: 


    with stdchannel_redirected(sys.stderr, os.devnull): 
     if compiler.has_function('clock_gettime', libraries=['rt']): 
      libraries.append('rt') 
    """ 

    try: 
     oldstdchannel = os.dup(stdchannel.fileno()) 
     dest_file = open(dest_filename, 'w') 
     os.dup2(dest_file.fileno(), stdchannel.fileno()) 

     yield 
    finally: 
     if oldstdchannel is not None: 
      os.dup2(oldstdchannel, stdchannel.fileno()) 
     if dest_file is not None: 
      dest_file.close() 

मैंने इसे क्यों बनाया है इसका संदर्भ this blog post पर है। आपके जैसा ही मुझे लगता है।

मैं एक setup.py में इस तरह इसका इस्तेमाल:

with stdchannel_redirected(sys.stderr, os.devnull): 
    if compiler.has_function('clock_gettime', libraries=['rt']): 
     libraries.append('rt') 
1

नहीं वास्तव में ओ पी से अनुरोध किया है, लेकिन मैं छिपाने के लिए और उत्पादन स्टोर करने के लिए इस प्रकार की तरह की जरूरत है, और आपने क्या किया:

from io import StringIO 
import sys 

class Hider: 
    def __init__(self, channels=('stdout',)): 
     self._stomach = StringIO() 
     self._orig = {ch : None for ch in channels} 

    def __enter__(self): 
     for ch in self._orig: 
      self._orig[ch] = getattr(sys, ch) 
      setattr(sys, ch, self) 
     return self 

    def write(self, string): 
     self._stomach.write(string) 

    def flush(self): 
     pass 

    def autopsy(self): 
     return self._stomach.getvalue() 

    def __exit__(self, *args): 
     for ch in self._orig: 
      setattr(sys, ch, self._orig[ch]) 

उपयोग:

with Hider() as h: 
    spammy_function() 
    result = h.autopsy() 

(केवल पायथो के साथ परीक्षण किया गया n 3)

संपादित करें: अब से stderr, stdout या दोनों, Hider([stdout, stderr])

+0

यह पाइथन 3 के लिए स्वीकार्य उत्तर होना चाहिए! कोई भी seld._stderr == sys.stderr जोड़ सकता है; sys.stderr = self <...> – neok

+0

@neok: सामान्यीकृत थोड़ा, सुझाव के लिए धन्यवाद –

संबंधित मुद्दे