def __init__(self, min_value=0, max_value=100, width=110, **kwargs): tty = isatty() self.silent = kwargs.get('silent', False) ## or not isatty() self.r = '\r' if tty else '\n' self.char = kwargs.get('char', '#') ## self.mode = kwargs.get('mode', 'fixed') ## fixed or dynamic if not self.mode in ['fixed', 'dynamic']: self.mode = 'fixed' self.bar = '' self.min = min_value self.max = max_value self.span = max(max_value - min_value, 1) self.last = '' ## ncols = columns() - 12 self.width = ncols if ncols > 10 else width self.prefix = kwargs.get('description', '') ## description self.width = self.width - len(self.prefix) self.amount = 0 self._hashes = -1 self.__end = None self.update_amount(self.min) self.build_bar() self.show() self.__start = time.time()
def frame_progress(self, length, width=None, symbol="#"): """ Draw (lazy) progress bar for the DataFrame: >>> f = DataFrame ( ... ) >>> p = f.ProgressBar ( 1000 ) ## number of elements! >>> .... """ cnt = self.Count() if not isatty(): return cnt left = "[ " right = " ]" minw = len(left) + len(right) + 3 + 1 + 1 + 1 length = length if isinstance(length, integer_types) and 0 < length else len(self) width = width if isinstance( width, integer_types) and 10 + minw <= width else terminal_size()[1] width = max(10, width - minw) nchunks = max(250, width + 1) csize, rr = divmod(length, nchunks) if rr: nchunks += 1 symbol = allright(symbol) fun = Ostap.Utils.frame_progress(nchunks, width, symbol, ' ', left, right) cnt.OnPartialResultSlot(csize, fun) return cnt
def colored_string(what, foreground=None, background=None, bold=False, blink=False, underline=False): """ >>> print colored_string ( 'Hello' , foreground = RED , background = YELLOW , bold = True , blink = True , underline = True ) """ ## nothing to colorize or no coloring is activated from ostap.utils.basic import isatty if not what or not with_colors() or not isatty(): return what ## nothing to do if (foreground is None) and (background is None): if (not bold) and (not blink) and (not underline): return what RESET_SEQ = "\033[0m" COLOR_SEQ = "\033[1;%dm" BOLD_SEQ = "\033[1m" if bold else '' BLINK_SEQ = "\033[5m" if blink else '' ULINE_SEQ = "\033[4m" if underline else '' fg = COLOR_SEQ % (30 + (foreground % 8)) if not foreground is None else '' bg = COLOR_SEQ % (40 + (background % 8)) if not background is None else '' return '{foreground}{background}{underline}{bold}{blink}{what}{reset}'.format( foreground=fg, background=bg, underline=ULINE_SEQ, bold=BOLD_SEQ, blink=BLINK_SEQ, what=what, reset=RESET_SEQ)
def make_colors(): """Colorize logging """ if with_colors(): return if not isatty(): return ## no colorization for non-TTY output global __with_colors__ __with_colors__ = True def makeName(level, fg=None, bg=None, blink=False, underline=False): name = logging.getLevelName(level) bold = fg is None and bg is None and not uderline return colored_string(name, fg, bg, bold, blink, underline) logging.addLevelName( logging.CRITICAL, makeName(logging.CRITICAL, fg=RED, bg=BLUE, blink=True)) logging.addLevelName( logging.WARNING, makeName(logging.WARNING, fg=RED, bg=YELLOW, underline=True)) logging.addLevelName( logging.ERROR, makeName(logging.ERROR, fg=YELLOW, bg=RED, blink=True)) logging.addLevelName(logging.INFO, makeName(logging.INFO, bg=BLUE, fg=WHITE)) logging.addLevelName(logging.DEBUG, makeName(logging.DEBUG, bg=GREEN, fg=WHITE)) return with_colors()
def __init__(self, min_value=0, max_value=100, width=110, **kwargs): self.silent = kwargs.get('silent', False) or not isatty() self.char = kwargs.get('char', '#') ## self.mode = kwargs.get('mode', 'fixed') ## fixed or dynamic if not self.mode in ['fixed', 'dynamic']: self.mode = 'fixed' self.bar = '' self.min = min_value self.max = max_value self.span = max(max_value - min_value, 1) ## ncols = columns() - 7 self.width = min(ncols, width) if ncols > 0 else width self.prefix = kwargs.get('description', '') ## description self.width = self.width - len(self.prefix) self.amount = 0 self._hashes = -1 self._percent = -1 self.update_amount(self.min) self.build_bar() self.show()
def frame_progress(self, length, width=None, symbol="#"): """ Draw (lazy) progress bar for the DataFrame: >>> f = DataFrame ( ... ) >>> p = f.ProgressBar ( 1000 ) ## number of elements! >>> .... """ cnt = self.Count() if not isatty(): return cnt length = length if isinstance(length, integer_types) and 0 < length else len(self) width = width if isinstance( width, integer_types) and 10 < width else terminal_size()[1] if width < 16: width = 16 nchunks = width - 14 csize = max(int(length / nchunks), 1) left = "[ " right = " ]" symbol = allright(symbol) fun = Ostap.Utils.frame_progress(csize, nchunks, symbol, ' ', left, right) cnt.OnPartialResultSlot(csize, fun) return cnt
def __init__(self, *args, **kwargs): self.silent = kwargs.get('silent', False) or not isatty() self.amount = 0 self.freq = int(kwargs.get('frequence', 100)) self.prefix = kwargs.get('description', '') self.update_amount()
def _ds_print2_(dataset): """Print dataset""" if dataset.isWeighted() and not isinstance(dataset, ROOT.RooDataHist): store = dataset.store() if valid_pointer(store) and isinstance(store, ROOT.RooTreeDataStore): pass else: return _ds_print_(dataset) from ostap.utils.basic import terminal_size, isatty if not isatty(): return _ds_table_(dataset) th, tw = terminal_size() rep, wid = _ds_table_0_(dataset) if wid < tw: return rep return _ds_print_(dataset)
def table(rows, title='', prefix=''): """Format the list of rows as a table. - Each row is a sequence of column cells. - The first row defines the column headers. When terminaltables package is accessible, use it to get nice pretty tables, otherwise use some home-made primitive replacement - see https://pypi.org/project/terminaltables - see https://github.com/Robpol86/terminaltables >>> table_data = [ ... ( 'Name' , 'Occupation' , 'Note' ) , ... ( 'Alice' , '?' , '---' ) , ... ( 'Bob' , 'unemployed' , '' ) ] >>> t = table ( table_data , 'Title' ) >>> print (t) """ from ostap.utils.basic import isatty title = allright(decolorize(title)) if rows: rows = list(rows) header_row = rows[0] header_row = [infostr(decolorize(c)) for c in header_row] rows[0] = header_row rows = tuple(rows) if terminaltables and isatty(): table_instance = terminaltables.SingleTable(rows, title) table_instance.justify_columns[0] = 'left' table_instance.justify_columns[2] = 'right' return add_prefix(table_instance.table, prefix) elif terminaltables: title = allright(title) table_instance = terminaltables.AsciiTable(rows, title) table_instance.justify_columns[0] = 'left' table_instance.justify_columns[2] = 'right' t = table_instance.table return add_prefix(table_instance.table, prefix) ## use the local replacement return the_table(rows, title, prefix)
logging.INFO: 'INFO ', logging.ERROR: 'ERROR ', logging.VERBOSE: 'VERBOSE' } for a in logging_levels: logging.addLevelName(a, logging_levels[a]) # ============================================================================= logging_format = '# %(name)-30s %(levelname)-7s %(message)s' logging_file_format = '# %(asctime)s %(name)-30s %(levelname)-7s %(message)s' logging_date_format = "%Y-%m-%d %H:%M:%S" from ostap.utils.basic import isatty # ============================================================================= ## The basic configuration if isatty(): logging.basicConfig( ## level = logging.NOTSET , level=1, format=logging_format, datefmt=logging_date_format) else: logging.basicConfig( ## level = logging.NOTSET , level=1, format=logging_file_format, datefmt=logging_date_format) # ============================================================================= ## Get current global threshold
# with keepColor() : # ... do something ... # @endcode def keepColor(): """Simple context manager to preserve color logging >>> with keepColor () : ... do something ... """ return KeepColorLogging() ## reset colors ## for ipython mode and TTY output activate colors ## if with_ipython() and isatty () : if isatty(): make_colors() ## define default logging thresholds as 'INFO' setLogging(3) # ============================================================================= if __name__ == '__main__': setLogging(0) logger = getLogger('ostap.logger') from ostap.utils.docme import docme docme(__name__, logger=logger)
def makeWeights( dataset, plots=[], database="weights.db", compare=None, ## comparison function delta=0.001, ## delta for ``mean'' weight variation minmax=0.05, ## delta for ``minmax'' weight variation power=0, ## auto-determination debug=True, ## save intermediate information in DB tag="Reweighting"): assert 0 < delta, "makeWeights(%s): Invalid value for ``delta'' %s" % ( tag, delta) assert 0 < minmax, "makeWeights(%s): Invalid value for ``minmax'' %s" % ( tag, minmax) from ostap.logger.colorized import allright, attention, infostr from ostap.utils.basic import isatty power = power if power >= 1 else len(plots) nplots = len(plots) if 1 < nplots: import math fudge_factor = math.sqrt(1.0 / max(2.0, nplots - 1.0)) delta = delta * fudge_factor minmax = minmax * fudge_factor save_to_db = [] ## number of active plots for reweighting for wplot in plots: what = wplot.what ## variable/function to plot/compare how = wplot.how ## weight and/or additional cuts address = wplot.address ## address in database hdata0 = wplot.data ## original "DATA" object hmc0 = wplot.mc_histo ## original "MC" histogram ww = wplot.w ## relative weight # # normailze the data # hdata = hdata0 if isinstance(hdata, ROOT.TH1): hdata = hdata.density() # ===================================================================== ## make a plot on (MC) data with the weight # ===================================================================== dataset.project(hmc0, what, how) st = hmc0.stat() mnmx = st.minmax() if iszero(mnmx[0]): logger.warning("Reweighting: statistic goes to zero %s/``%s''" % (st, address)) # ===================================================================== ## normalize MC # ===================================================================== hmc = hmc0.density() # ===================================================================== ## calculate the reweighting factor : a bit conservative (?) # this is the only important line # ===================================================================== # try to exploit finer binning if/when possible if isinstance ( hmc , ( ROOT.TH1F , ROOT.TH1D ) ) and \ isinstance ( hdata , ( ROOT.TH1F , ROOT.TH1D ) ) and \ len ( hmc ) >= len( hdata ) : w = (1.0 / hmc) * hdata ## NB! ## elif isinstance ( hmc , ( ROOT.TH2F , ROOT.TH2D ) ) and \ ## isinstance ( hdata , ( ROOT.TH2F , ROOT.TH2D ) ) and \ ## len ( hmc.GetXaxis() ) >= len( hdata.GetXaxis () ) and \ ## len ( hmc.GetYaxis() ) >= len( hdata.GetYaxis () ) : w = ( 1.0 / hmc ) * hdata ## NB! ## elif isinstance ( hmc , ( ROOT.TH3F , ROOT.TH3D ) ) and \ ## isinstance ( hdata , ( ROOT.TH3F , ROOT.TH3D ) ) and \ ## len ( hmc.GetXaxis() ) >= len( hdata.GetXaxis () ) and \ ## len ( hmc.GetYaxis() ) >= len( hdata.GetYaxis () ) and \ ## len ( hmc.GetZaxis() ) >= len( hdata.GetZaxis () ) : w = ( 1.0 / hmc ) * hdata ## NB! else: w = hdata / hmc ## NB! # ===================================================================== ## scale & get the statistics of weights w /= w.stat().mean().value() cnt = w.stat() # mnw, mxw = cnt.minmax() wvar = cnt.rms() / cnt.mean() good1 = wvar.value() <= delta good2 = abs(mxw - mnw) <= minmax good = good1 and good2 ## small variance? # afunc1 = allright if good1 else attention afunc2 = allright if good2 else attention # message = "%s: %24s:" % (tag, address) message += ' ' + 'mean=%12s' % cnt.mean().toString('(%4.2f+-%4.2f)') message += ' ' + afunc2('min/max=%-5.3f/%5.3f' % (cnt.minmax()[0], cnt.minmax()[1])) message += ' ' + afunc1('rms=%s[%%]' % (wvar * 100).toString('(%4.2f+-%4.2f)')) logger.info(message) # ## make decision based on the variance of weights # mnw, mxw = cnt.minmax() if good: ## small variance? message = "%s: No more reweights for %s" % (tag, address) message += ' ' + allright("min/max/rms=%+3.1f/%+3.1f/%3.1f[%%]" % ((mnw - 1) * 100, (mxw - 1) * 100, 100 * wvar)) logger.info(message) del w, hdata, hmc else: save_to_db.append((address, ww, hdata0, hmc0, hdata, hmc, w)) # ===================================================================== ## make a comparison (if needed) # ===================================================================== if compare: compare(hdata0, hmc0, address) ## for single reweighting ## if 1 == nplots : power = 1 ## if power != nplots : # logger.info ( "%s: ``power'' is %g/#%d" % ( tag , power , nplots ) ) active = [p[0] for p in save_to_db] all = [p.address for p in plots] for i, a in enumerate(all): if a in active: if isatty(): all[i] = attention(a) else: all[i] = '*' + a + '*' else: if isatty(): all[i] = allright(a) logger.info("%s: reweights are: %s" % (tag, (', '.join(all)))) ## if len ( active ) != nplots : ## if database and save_to_db : ## power += ( nplots - len ( active ) ) ## logger.info ("%s: ``power'' is changed to %g" % ( tag , power ) ) nactive = len(active) while database and save_to_db: entry = save_to_db.pop() address, ww, hd0, hm0, hd, hm, weight = entry ## eff_exp = 1.0 / power ## eff_exp = 0.95 / ( 1.0 * nactive ) ** 0.5 cnt = weight.stat() mnw, mxw = cnt.minmax() if 0.95 < mnw and mxw < 1.05: eff_exp = 0.75 if 1 < nactive else 1.50 elif 0.90 < mnw and mxw < 1.10: eff_exp = 0.70 if 1 < nactive else 1.30 elif 0.80 < mnw and mxw < 1.20: eff_exp = 0.65 if 1 < nactive else 1.25 elif 0.70 < mnw and mxw < 1.30: eff_exp = 0.60 if 1 < nactive else 1.15 elif 0.50 < mnw and mxw < 1.50: eff_exp = 0.55 if 1 < nactive else 1.10 else: eff_exp = 0.50 if 1 < nactive else 1.0 ## print 'effective exponent is:', eff_exp , address , mnw , mxw , (1.0/mnw)*mnw**eff_exp , (1.0/mxw)*mxw**eff_exp if 1 < nactive and 1 != ww: eff_exp *= ww logger.info("%s: apply ``effective exponent'' of %.3f for ``%s''" % (tag, eff_exp, address)) if 1 != eff_exp and 0 < eff_exp: weight = weight**eff_exp ## print 'WEIGHT stat', eff_exp, weight.stat() ## hmmmm... needed ? yes! #if 1 < power : weight = weight ** ( 1.0 / power ) ## relative importance #if 1 != ww : # logger.info ("%s: apply ``relative importance factor'' of %.3g for ``'%s'" % ( tag , ww , address ) ) # weight = weight ** ww with DBASE.open(database) as db: db[address] = db.get(address, []) + [weight] if debug: addr = address + ':REWEIGHTING' db[addr] = db.get(addr, []) + list(entry[2:]) del hd0, hm0, hd, hm, weight, entry return active
def __init__ ( self , name , variables , weights_files , options = '' , verbose = True ) : """Constrct the reader >>> from ostap.tools.tmva import Reader >>> r = Reader ( 'MyTMVA' , ... variables = [ ## name accessor ... ( 'pt' , lambda s : s.pt ) , ... ( 'ip' , lambda s : s.ip ) , ... 'var1' , ## s.var1 will be used ... 'var2' ] , ## s.var2 will be used ... weights_files = 'my_weights.xml' ) - attention: It is *not* CPU-efficient: Ugly tricks with arrays are required to bypass some technical limitations weights_fiels can be : - single xml-file with weights for the given method - single tar/tgz/tar.gz-file with weights files - list of xml-files with weights If the xml-filenames follow TMVA Trainer convention, the training method will be extracted from the file name, otherwise it needs to be specified as dictionary with the key being the method name, or list of 2-element tuples : >>> weights_files = { 'MPL':'my_weights.xml' , 'BDTG':'weights2.xml' } >>> weights_files = [ ('MPL','my_weights.xml') , ('BDTG','weights2.xml') ] """ ROOT.TMVA.Tools.Instance() verbose = True if verbose else False options = opts_replace ( options , 'V:' , verbose ) options = opts_replace ( options , 'Silent:' , not verbose ) from ostap.utils.basic import isatty optiont = opts_replace ( options , 'Color:' , verbose and isatty() ) self.__reader = ROOT.TMVA.Reader( options , verbose ) self.__name = name ## treat the weigths files weights = WeightsFiles ( weights_files ) ## book the variables: # dirty trick with arrays is needed due to a bit strange reader interface. # [TMVA reader needs the address of ``float''(in C++ sense) variable] from array import array self.__variables = [] for v in variables : if isinstance ( v , str ) : vname = v fvun = lambda s : getattr ( s , vname ) vfield = array ( 'f' , [1] ) ## NB: note the type elif isinstance ( v , tuple ) and 2 == len ( v ) : vname = v[0] vfun = v[1] vfield = array ( 'f' , [1] ) ## NB: note the type here else : logger.error ('Reader(%s): Invalid variable description!' % name ) raise AttributeError, 'Invalid variable description!' ## name accessor address self.__variables += [ ( vname , vfun , vfield ) ] self.__variables = tuple ( self.__variables ) ## declare all variables to TMVA.Reader for v in self.__variables : self.__reader.AddVariable ( v[0] , v[2] ) self.__methods = weights.methods for method , xml in weights.files.iteritems() : m = self.__reader.BookMVA ( method , xml ) assert m , 'Error in booking %s/%s' % ( method , xml ) logger.debug ('TMVA Reader(%s) is booked for method:%s xml: %s' % ( self.__name , method , xml ) ) logger.info ('TMVA Reader(%s) booked methods are %s' % ( self.__name , self.__methods ) ) self.__methods = tuple ( self.__methods )
def __init__( self , methods , variables , # list of variables signal , # signal sample/tree background , # background sample/tree signal_cuts = '' , # signal cuts background_cuts = '' , # background cuts spectators = [] , bookingoptions = "Transformations=I;D;P;G,D" , configuration = "nTrain_Signal=0:nTrain_Background=0:SplitMode=Random:NormMode=NumEvents" , signal_weight = None , background_weight = None , ## output_file = '' , # the name of output file verbose = True , name = 'TMVA' ) : """Constructor with list of methods >>> from ostap.tools.tmva import Trainer >>> t = Trainer( ... ## TMVA methods ... methods = [ ( ROOT.TMVA.Types.kMLP , ... 'MLP', ... 'H:!V:EstimatorType=CE:VarTransform=N:NCycles=600:HiddenLayers=N+7:TestRate=5:!UseRegulator' ) ] , ... variables = [ 'dtfchi2' , 'ctau', 'ptb' , 'vchi2' ] , ## list of variables ... signal = treeSignal , ## TTree for ``signal'' sample ... background = treeBackgrund , ## TTree for ``background'' sample ... signal_cuts = cuts_for_signal , ... background_cuts = cuts_for_background ) - For more detailes see http://www.slac.stanford.edu/grp/eg/minos/ROOTSYS/cvs/tmva/test/TMVAClassification.py. """ self.__methods = tuple ( methods ) self.__variables = tuple ( variables ) from ostap.trees.trees import Chain if isinstance ( signal , Chain ) : signal = signal.chain if isinstance ( background , Chain ) : background = background.chain self.__signal = signal self.__signal_cuts = signal_cuts self.__signal_weight = signal_weight self.__background = background self.__background_cuts = background_cuts self.__background_weight = background_weight self.__spectators = [] self.__verbose = True if verbose else False self.__name = name self.__bookingoptions = bookingoptions self.__configuration = configuration ## outputs self.__weights_files = [] self.__class_files = [] self.__output_file = output_file if output_file else '%s.root' % self.name self.__tar_file = None self.__log_file = None # ## minor adjustment # opts = self.__bookingoptions if 0 > opts.find ( "AnalysisType=" ) : opts += ":AnalysisType=Classification" logger.debug('Trainer(%s): booking options are appended with ":AnalysisType=Classification"' % name ) opts = opts_replace ( opts , 'V:' , self.verbose ) opts = opts_replace ( opts , 'Silent:' , not self.verbose ) from ostap.utils.basic import isatty opts = opts_replace ( opts , 'DrawProgressBar:' , self.verbose and isatty() ) opts = opts_replace ( opts , 'Color:' , self.verbose and isatty() ) _methods = [] for _m in self.methods : _m = list( _m ) _m[2] = opts_replace ( _m[2] , 'H:' , self.verbose ) _methods.append ( tuple ( _m ) ) self.__methods = tuple ( _methods ) self.__bookingoptions = str ( opts ) ## clean-up dirname = str( self.name ) for s in ( ' ' , '%' , '!' , '>' , '<' , '\n' , '?' ) : while s in dirname : dirname = dirname.replace ( ' ' , '_' ) pattern_xml = pattern_XML % ( dirname , dirname ) pattern_C = pattern_CLASS % ( dirname , dirname ) rf = [] import glob,os for f in glob.glob ( pattern_xml ) : rf.append ( f ) os.remove ( f ) for f in glob.glob ( pattern_C ) : rf.append ( f ) os.remove ( f ) if rf : logger.debug ( "Trainer(%s): remove existing xml/class-files %s" % ( self.name , rf ) ) self.__dirname = dirname self.__pattern_xml = pattern_xml self.__pattern_C = pattern_C
def with_colors(): """Is colorization enabled ?""" global __with_colors__ return bool(__with_colors__) and isatty()
def table(rows, title='', prefix='', alignment=(), wrap_width=-1, indent=wrap_indent): """Format the list of rows as a table. - Each row is a sequence of column cells. - The first row defines the column headers. When terminaltables package is accessible, use it to get nice pretty tables, otherwise use some home-made primitive replacement - see https://pypi.org/project/terminaltables - see https://github.com/Robpol86/terminaltables >>> table_data = [ ... ( 'Name' , 'Occupation' , 'Note' ) , ... ( 'Alice' , '?' , '---' ) , ... ( 'Bob' , 'unemployed' , '' ) ] >>> t = table ( table_data , 'Title' ) >>> print (t) """ from ostap.utils.basic import isatty title = allright(decolorize(title)) if rows: rows = list(rows) header_row = rows[0] header_row = [infostr(decolorize(c)) for c in header_row] rows[0] = header_row rows = tuple(rows) rows = [list(row) for row in rows] if not terminaltables: ## use the local replacement return the_table(rows, title, prefix, alignment=alignment) if isatty(): title = allright(title) table_instance = terminaltables.SingleTable(rows, title) else: title = allright(title) table_instance = terminaltables.AsciiTable(rows, title) cw = table_instance.column_widths nc = len(cw) wraps = [i for (i, a) in enumerate(alignment) if a in wrapped] if wraps: from terminaltables.width_and_alignment import max_dimensions widths = max_dimensions(table_instance.table_data, table_instance.padding_left, table_instance.padding_right)[2] widths = sum(l for (i, l) in enumerate(widths) if not i in wraps) widths += nc + 1 + len(prefix) + 4 + 2 * len(wraps) _, w = terminal_size() ww = w - widths ww, _ = divmod(ww, len(wraps)) if 12 < ww and ww < wrap_width: wrap_width = ww elif 12 < ww and wrap_width <= 0: wrap_width = ww if wrap_width < 12: wrap_width = max_width nw = len(wraps) for i, a in zip(range(nc), alignment): if a and isinstance(a, str): al = a.lower() if al in left: table_instance.justify_columns[i] = 'left' elif al in right: table_instance.justify_columns[i] = 'right' elif al in center: table_instance.justify_columns[i] = 'center' elif al in wrapped: maxw = table_instance.column_max_width(i) if 15 < wrap_width * nw < maxw: maxw = (wrap_width - 3) * nw if 1 < nw else wrap_width if maxw < 15: maxw = (wrap_width - 3) * nw if 1 < nw else wrap_width if maxw < 15: maxw = (max_width - 3) * nw if 1 < nw else max_width width = maxw / nw if 1 < nw else maxw for l, line in enumerate(table_instance.table_data): if width < len(line[i]): table_instance.table_data[l][i] = textwrap.fill( indent + line[i], wrap_width) return add_prefix(table_instance.table, prefix)
# @code # with keepColor() : # ... do something ... # @endcode def keepColor(): """Simple context manager to preserve color logging >>> with keepColor () : ... do something ... """ return KeepColorLogging() ## reset colors ## for ipython mode and TTY output activate colors if with_ipython() and isatty(): make_colors() ## define default logging thresholds as 'INFO' setLogging(3) # ============================================================================= if __name__ == '__main__': setLogging(0) logger = getLogger('ostap.logger') from ostap.utils.docme import docme docme(__name__, logger=logger)