# Description: Reporting
# Documentation: algorithms.txt
from __future__ import print_function
import six
class Scope(object):
def __init__(self, name):
self.name = name
self.textSet = []
self.reportIndex = 0
def insert(self, text, type):
self.textSet.append((text, type))
class ScopeGuard(object):
def __init__(self, reporter, name):
self.name_ = name
self.reporter_ = reporter
self.open_ = False
def __enter__(self):
self.open()
def __exit__(self, type, value, traceback):
self.close()
def name(self):
return self.name_
def isOpen(self):
return self.open_
def open(self):
if not self.open_:
self.reporter_.openScope(self.name_)
self.open_ = True
def close(self):
if self.open_:
self.reporter_.closeScope(self.name_)
self.open_ = False
class Reporter(object):
def __init__(self):
# A set of reporting scopes.
self.scopeSet = []
self.disabledSet = set()
self.warnings_ = 0
self.errors_ = 0
self.scopeSet.append(Scope('global'))
self.spaceBeforeNext = False
def errors(self):
return self.errors_
def warnings(self):
return self.warnings_
def openScope(self, name):
scope = Scope(name)
self.scopeSet.append(scope)
text = [None]
text += self.heading(name, len(self.scopeSet) - 1)
text.append(None)
self.report(text, 'heading', True)
def closeScope(self, name):
assert len(self.scopeSet) > 0 and name == self.scopeSet[-1].name
self.scopeSet.pop()
def enable(self, type, value = True):
if value:
if type in self.disabledSet:
self.disabledSet.remove(type)
else:
if not type in self.disabledSet:
self.disabledSet.add(type)
def disable(self, type):
self.enable(type, False)
def enabled(self, type):
return type not in self.disabledSet
def report(self, text, type, lazy = False):
if isinstance(text, six.string_types) or (text is None):
self.report([text], type, lazy)
return
if self.enabled(type):
self.scope().insert(text, type)
if not lazy:
self.updatePrint()
def reportWarning(self, text, type):
if isinstance(text, six.string_types):
self.reportWarning([text], type)
return
if len(text) > 0:
text = [None, '[' + type + ']'] + text + [None];
self.report(text, type, False)
if self.enabled(type):
self.warnings_ += 1
def reportDebug(self, text, type):
if isinstance(text, six.string_types):
self.reportWarning([text], type)
return
if len(text) > 0:
text = [None, '[' + type + ']'] + text + [None];
self.report(text, type, False)
def reportError(self, text, type):
if isinstance(text, six.string_types):
self.reportError([text], type)
return
if len(text) > 0:
text = [None, '[' + type + ']!'] + text + [None]
self.report(text, type, False)
self.errors_ += 1
def reportAmbiguousDocument(self, path):
self.reportWarning('Document ' + path + ' is ambiguous. Picking arbitrarily.',
'ambiguous-document')
def reportMissingDocument(self, path):
self.reportWarning('Document ' + path + ' not found. Ignoring it.',
'missing-document')
# Private
def heading(self, name, level):
text = []
if level == 1:
text.append(name)
text.append('=' * max(len(name), 3))
elif level == 2:
text.append(name)
text.append('-' * max(len(name), 3))
else:
text.append('#' * level + ' ' + name)
return text
def scope(self):
return self.scopeSet[-1]
def updatePrint(self):
for scope in self.scopeSet:
n = len(scope.textSet)
for i in range(scope.reportIndex, n):
(text, type) = scope.textSet[i]
if self.enabled(type):
#print('(' + type + ')')
for line in text:
if line is None:
self.spaceBeforeNext = True
continue
if self.spaceBeforeNext:
print()
self.spaceBeforeNext = False
print(line)
#print(line.encode("ascii", "backslashreplace"))
scope.reportIndex = n