[tor-commits] [stem/master] Don't use stdout/stderr directly for python output

atagar at torproject.org atagar at torproject.org
Sun Jul 31 23:04:05 UTC 2016


commit ae48d813dafcae8f46f50d35b758dd5287d178cf
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Jul 31 15:59:47 2016 -0700

    Don't use stdout/stderr directly for python output
    
    Python interpreter commands use the builtin InteactiveConsole which interacts
    with stdout and stderr directly. This isn't a problem for our tor-prompt since
    it writes to stdout anyway, but it breaks nyx.
    
    Nicest option I've found for this is...
    
      https://stackoverflow.com/questions/13250050/redirecting-the-output-of-a-python-function-from-stdout-to-variable-in-python
---
 stem/interpreter/commands.py | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/stem/interpreter/commands.py b/stem/interpreter/commands.py
index 82a216d..e348c6e 100644
--- a/stem/interpreter/commands.py
+++ b/stem/interpreter/commands.py
@@ -6,7 +6,9 @@ Handles making requests and formatting the responses.
 """
 
 import code
+import contextlib
 import socket
+import sys
 
 import stem
 import stem.control
@@ -19,6 +21,11 @@ import stem.util.tor_tools
 from stem.interpreter import STANDARD_OUTPUT, BOLD_OUTPUT, ERROR_OUTPUT, uses_settings, msg
 from stem.util.term import format
 
+try:
+  from cStringIO import StringIO
+except ImportError:
+  from io import StringIO
+
 
 def _get_fingerprint(arg, controller):
   """
@@ -84,6 +91,17 @@ def _get_fingerprint(arg, controller):
     raise ValueError("'%s' isn't a fingerprint, nickname, or IP address" % arg)
 
 
+ at contextlib.contextmanager
+def redirect(stdout, stderr):
+  original = sys.stdout, sys.stderr
+  sys.stdout, sys.stderr = stdout, stderr
+
+  try:
+    yield
+  finally:
+    sys.stdout, sys.stderr = original
+
+
 class ControlInterpreter(code.InteractiveConsole):
   """
   Handles issuing requests and providing nicely formed responses, with support
@@ -338,8 +356,13 @@ class ControlInterpreter(code.InteractiveConsole):
         is_tor_command = cmd in config.get('help.usage', {}) and cmd.lower() != 'events'
 
         if self._run_python_commands and not is_tor_command:
-          self.is_multiline_context = code.InteractiveConsole.push(self, command)
-          return
+          console_output = StringIO()
+
+          with redirect(console_output, console_output):
+            self.is_multiline_context = code.InteractiveConsole.push(self, command)
+
+          output = console_output.getvalue()
+          return output if output else None
         else:
           try:
             output = format(self._controller.msg(command).raw_content().strip(), *STANDARD_OUTPUT)



More information about the tor-commits mailing list