Add CaptureStd context manager for capturing stdout and stderr

This commit is contained in:
Matt Martz 2016-02-20 11:54:05 -06:00 committed by John Barker
parent 60a2165987
commit 75b299e6de
2 changed files with 53 additions and 46 deletions

View file

@ -10,9 +10,6 @@ import re
import sys import sys
import traceback import traceback
# We only use StringIO, since we cannot setattr on cStringIO
from StringIO import StringIO
from distutils.version import StrictVersion from distutils.version import StrictVersion
from fnmatch import fnmatch from fnmatch import fnmatch
@ -22,7 +19,7 @@ from ansible.module_utils import basic as module_utils_basic
from ansible.plugins import module_loader from ansible.plugins import module_loader
from ansible.utils.module_docs import BLACKLIST_MODULES, get_docstring from ansible.utils.module_docs import BLACKLIST_MODULES, get_docstring
from utils import find_globals from utils import CaptureStd, find_globals
import yaml import yaml
@ -359,24 +356,17 @@ class ModuleValidator(Validator):
except AttributeError: except AttributeError:
self.errors.append('No DOCUMENTATION provided') self.errors.append('No DOCUMENTATION provided')
else: else:
sys_stdout = sys.stdout with CaptureStd():
sys_stderr = sys.stderr try:
sys.stdout = sys.stderr = buf = StringIO() get_docstring(self.path, verbose=True)
# instead of adding noqa to the above, do something with buf except AssertionError:
assert buf fragment = doc['extends_documentation_fragment']
setattr(sys.stdout, 'encoding', sys_stdout.encoding) self.errors.append('DOCUMENTATION fragment missing: %s' %
setattr(sys.stderr, 'encoding', sys_stderr.encoding) fragment)
try: except Exception as e:
get_docstring(self.path, verbose=True) self.traces.append(e)
except AssertionError: self.errors.append('Unknown DOCUMENTATION error, see '
fragment = doc['extends_documentation_fragment'] 'TRACE')
self.errors.append('DOCUMENTATION fragment missing: %s' % fragment)
except Exception as e:
self.traces.append(e)
self.errors.append('Unknown DOCUMENTATION error, see TRACE')
finally:
sys.stdout = sys_stdout
sys.stderr = sys_stderr
self._check_version_added(doc) self._check_version_added(doc)
self._check_for_new_args(doc) self._check_for_new_args(doc)
@ -435,30 +425,21 @@ class ModuleValidator(Validator):
if self._is_new_module(): if self._is_new_module():
return return
sys_stdout = sys.stdout with CaptureStd():
sys_stderr = sys.stderr try:
sys.stdout = sys.stderr = buf = StringIO() existing = module_loader.find_plugin(self.name, mod_type='.py')
# instead of adding noqa to the above, do something with buf existing_doc, _, _ = get_docstring(existing, verbose=True)
assert buf existing_options = existing_doc.get('options', {})
setattr(sys.stdout, 'encoding', sys_stdout.encoding) except AssertionError:
setattr(sys.stderr, 'encoding', sys_stderr.encoding) fragment = doc['extends_documentation_fragment']
try: self.errors.append('Existing DOCUMENTATION fragment missing: '
existing = module_loader.find_plugin(self.name, mod_type='.py') '%s' % fragment)
existing_doc, _, _ = get_docstring(existing, verbose=True) return
existing_options = existing_doc.get('options', {}) except Exception as e:
except AssertionError: self.traces.append(e)
fragment = doc['extends_documentation_fragment'] self.errors.append('Unknown existing DOCUMENTATION error, see '
self.errors.append('Existing DOCUMENTATION fragment missing: %s' % 'TRACE')
fragment) return
return
except Exception as e:
self.traces.append(e)
self.errors.append('Unknown existing DOCUMENTATION error, see '
'TRACE')
return
finally:
sys.stdout = sys_stdout
sys.stderr = sys_stderr
options = doc.get('options', {}) options = doc.get('options', {})

View file

@ -1,4 +1,8 @@
import ast import ast
import sys
# We only use StringIO, since we cannot setattr on cStringIO
from StringIO import StringIO
def find_globals(g, tree): def find_globals(g, tree):
@ -22,3 +26,25 @@ def find_globals(g, tree):
if g_name == '*': if g_name == '*':
continue continue
g.add(g_name) g.add(g_name)
class CaptureStd():
"""Context manager to handle capturing stderr and stdout"""
def __enter__(self):
self.sys_stdout = sys.stdout
self.sys_stderr = sys.stderr
sys.stdout = self.stdout = StringIO()
sys.stderr = self.stderr = StringIO()
setattr(sys.stdout, 'encoding', self.sys_stdout.encoding)
setattr(sys.stderr, 'encoding', self.sys_stderr.encoding)
return self
def __exit__(self, exc_type, exc_value, traceback):
sys.stdout = self.sys_stdout
sys.stderr = self.sys_stderr
def get(self):
"""Return ``(stdout, stderr)``"""
return self.stdout.getvalue(), self.stderr.getvalue()