"""
.. module:: basicPrinter
:synopsis: Base class for defining printer classes
.. moduleauthor:: Andre Lessa <lessa.a.p@gmail.com>
"""
import sys
import os
from smodels.base.smodelsLogging import logger
import numpy as np
import time
[docs]class BasicPrinter(object):
"""
Super class to handle the basic printing methods
"""
def __init__(self, output, filename, outputFormat = 'current'):
"""
:ivar str typeofexpectedvalues: what type of expected values to print,
apriori or posteriori
"""
self.name = "basic"
self.time = time.time() # time stamps
self.outputList = []
self.filename = filename
self.output = output
self.printingOrder = []
self.typeofexpectedvalues = "apriori"
self.toPrint = []
self.outputFormat = outputFormat
if filename and os.path.isfile(filename):
logger.warning("Removing file %s" % filename)
os.remove(filename)
[docs] def getTypeOfExpected(self):
""" tiny convenience function for what expected values to print,
apriori (True) or posteriori """
expected = True
if self.typeofexpectedvalues == "posteriori":
expected = "posteriori"
return expected
@property
def filename(self):
return self._filename
@filename.setter
def filename(self, fn):
self._filename = fn
self.mkdir()
[docs] def mkdir(self):
""" create directory to file, if necessary """
if not self.filename:
return
dirname = os.path.dirname(self.filename)
if dirname != "" and not os.path.exists(dirname):
os.makedirs(dirname)
[docs] def setOptions(self, options):
"""
Store the printer specific options to control the output of each printer.
Each option is stored as a printer attribute.
:param options: a list of (option,value) for the printer.
"""
for opt, value in options:
setattr(self, opt, eval(value))
[docs] def addObj(self, obj):
"""
Adds object to the Printer.
:param obj: A object to be printed. Must match one of the types defined in formatObj
:return: True if the object has been added to the output. If the object does not belong
to the pre-defined printing list toPrint, returns False.
"""
for iobj, objType in enumerate(self.printingOrder):
if isinstance(obj, objType):
self.toPrint[iobj] = obj
return True
return False
[docs] def openOutFile(self, filename, mode):
""" creates and opens a data sink,
creates path if needed """
d = os.path.dirname(filename)
if not os.path.exists(d):
os.makedirs(d)
logger.info("creating directory %s" % d)
return open(filename, mode)
[docs] def flush(self):
"""
Format the objects added to the output, print them to the screen
or file and remove them from the printer.
"""
ret = ""
for obj in self.toPrint:
if obj is None:
continue
output = self._formatObj(obj)
if not output:
continue # Skip empty output
ret += output
if self.output == 'stdout':
sys.stdout.write(output)
elif self.output == 'file':
if not self.filename:
logger.error('Filename not defined for printer')
return False
with self.openOutFile(self.filename, "a") as outfile:
outfile.write(output)
outfile.close()
self.toPrint = [None]*len(self.printingOrder) # Reset printing objects
self.time = time.time() # prepare next timestamp
return ret
def _formatObj(self, obj):
"""
Method for formatting the output depending on the type of object
and output.
:param obj: A object to be printed. Must match one of the types defined in formatObj
"""
typeStr = type(obj).__name__
try:
formatFunction = getattr(self, '_format'+typeStr)
ret = formatFunction(obj)
# print ( " `-", len(ret))
return ret
except AttributeError as e:
logger.warning('Error formating object %s: \n %s' % (typeStr, e))
return False
def _round(self, number, n=6):
""" round a number to n significant digits, if it *is* a number """
if type(number) not in [float, np.float64]:
return number
if not np.isfinite(number):
return f'float("{number}")'
if np.isnan(number) or not np.isfinite(number):
return number
try:
if abs(number) < 1e-40:
return number
return round(number, -int(np.floor(np.sign(number) * np.log10(abs(number)))) + n)
except Exception:
pass
return number
# return round ( number, n )