Debug Tools
std_capture.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 
38 
39 import io
40 import re
41 import sys
42 
43 import inspect
44 import traceback
45 
46 
47 class TeeNoFile(object):
48  """
49  How do I duplicate sys.stdout to a log file in python?
50  https://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log-file-in-python
51  """
52  __closed = False
53 
54  def __init__(self, stdout=False, ignoredefault=False):
55  """ If `ignoredefault` is True, only write to this object stream.
56  """
57  self._contents = []
58  self.stdout_type = stdout
59 
60  if stdout:
61  self._std_original = sys.stdout
62  sys.stdout = self
63 
64  else:
65  self._std_original = sys.stderr
66  sys.stderr = self
67 
68  if ignoredefault:
69  self.write = self.writethis
70  else:
71  self.write = self.writeboth
72 
73  # sys.stdout.write( "inspect.getmro(sys.stderr): %s\n" % str( inspect.getmro( type( sys.stderr ) ) ) )
74  # sys.stdout.write( "inspect.getmro(self.stderr): %s\n" % str( inspect.getmro( type( self._std_original ) ) ) )
75 
76  @property
77  def closed(self):
78  """
79  @return `True` if the file has been closed.
80  """
81  return self.__closed
82 
83  def __del__(self):
84  """
85  The try/except block is in case this is called at program exit time, when it's possible
86  that globals have already been deleted, and then the close() call might fail. Since
87  there's nothing we can do about such failures and they annoy the end users, we suppress
88  the traceback.
89  https://github.com/python/cpython/blob/1fd06f1eca80dcbf3a916133919482a8327f3da4/Lib/_pyio.py#L380
90 
91  python Exception AttributeError: “'NoneType' object has no attribute 'var'”
92  https://stackoverflow.com/questions/9750308/python-exception-attributeerror-nonetype-object-has-no-attribute-var
93  """
94 
95  try:
96  self.close()
97 
98  except:
99  pass
100 
101  def clear(self, log=None):
102  if log is not None:
103  log.clear()
104  del self._contents[:]
105 
106  def flush(self):
107 
108  try:
109  self._std_original.flush()
110 
111  except AttributeError:
112 
113  if self.closed:
114  pass
115 
116  else:
117  raise
118 
119  def writeboth(self, *args, **kwargs):
120  # self._std_original.write( " 111111 %s" % self._std_original.write + str( args ), **kwargs )
121  # self._contents.append( " 555555" + str( args ), **kwargs )
122  self._std_original.write( *args, **kwargs )
123  self._contents.append( *args, **kwargs )
124 
125  def writethis(self, *args, **kwargs):
126  self._contents.append( *args, **kwargs )
127 
128  write = writeboth
129 
130  def contents(self, date_regex=""):
131  contents = self._process_contents( date_regex, "".join( self._contents ) )
132  return contents
133 
134  def file_contents(self, log, date_regex=""):
135 
136  with io.open( log.output_file, "r", encoding='utf-8', newline=None ) as file:
137  output = file.read()
138 
139  contents = self._process_contents( date_regex, output )
140  self._std_original.write("\nContents:\n`%s`\n" % contents)
141  return contents
142 
143  def _process_contents(self, date_regex, output):
144  clean_output = []
145  date_regex_pattern = re.compile( date_regex )
146 
147  output = output.strip().split( "\n" )
148 
149  for line in output:
150  clean_output.append( date_regex_pattern.sub( "", line ) )
151 
152  return "\n".join( clean_output )
153 
154  def close(self):
155 
156  # On shutdown `__del__`, the sys module can be already set to None.
157  if sys and self._std_original and not self.__closed:
158 
159  try:
160  self.flush()
161 
162  finally:
163  self.__closed = True
164 
165  if self.stdout_type:
166  sys.stdout = self._std_original
167 
168  else:
169  sys.stderr = self._std_original
170 
171  self._std_original = None
def __init__(self, stdout=False, ignoredefault=False)
Definition: std_capture.py:54
def writeboth(self, args, kwargs)
Definition: std_capture.py:119
def writethis(self, args, kwargs)
Definition: std_capture.py:125
def _process_contents(self, date_regex, output)
Definition: std_capture.py:143