Package: log21
log21A simple logging package that helps you log colorized messages in Windows console and other operating systems.FeaturesColors : The main reason for this package was to log text in the Windows console with the support of ANSI colors.Argument parsing : log21's argument parser can be used like python's argparse but it also colorizes the output.Logging : A similar logger to logging. Logger but with colorized output and other options such as levelname
modifications. It can also decolorize the output if you want to log into a file.Pretty printing : Have you ever wanted to colorize the output of the pprint module? log21's pretty printer can do
that.Tree printing : You can pass a dict or list tolog21.tree_printfunction and it will print it in a tree-like
structure. It's also colorized XD.ProgressBar : log21's progress bar can be used to show progress of a process in a beautiful way.LoggingWindow : Helps you to log messages and debug your code in a window other than the console.CrashReporter : log21's crash reporter can be used to report crashes in different
ways. You can use it to log crashes to console or files or use it to receive crash
reports of your program through email. And you can also define your own crash
reporter functions and use them instead!Argumentify : You can use the argumentify feature to decrease the number of lines you
need to write to parse command-line arguments. It's colored by the way!Any idea? Feel free toopen an issueor submit a pull request.InstallationWell, this is a python package so the first thing you need is python.If you don't have python installed, please visitPython.organd install the latest version of
python.Then you can install log21 using pip module:python-mpipinstalllog21-UOr you can clonethe repositoryand run:pipinstall.Or let the pip get it using git:pipinstallgit+https://github.com/MPCodeWriter21/log21Changes2.8.0Update python versionRenamedcrash_report.logto.crash_report.log.Added "force" error handling method toLogger.add_level.Changed the adding level error handling method to "ignore".Ability to add new methods to the Logger object for each custom level.Full CHANGELOGUsage Examples:Basic Loggingimportlog21log21.print(log21.get_color('#FF0000')+'This'+log21.get_color((0,255,0))+' is'+log21.get_color('Blue')+' Blue'+log21.get_colors('BackgroundWhite','Black')+' 8)')logger=log21.get_logger('My Logger',level_names={21:'SpecialInfo',log21.WARNING:' ! ',log21.ERROR:'!!!'})logger.info('You are reading the README.md file...')logger.log(21,'Here','%s','GO!',args=('we',))logger.setLevel(log21.WARNING)logger.warning("We can't log messages with a level less than 30 anymore!")logger.debug("You won't see this!")logger.info("Am I visible?")logger.error(log21.get_colors('LightRed')+"I'm still here ;1")Argument Parsing (See Also:Argumentify)importlog21fromlog21importColorizingArgumentParser,get_logger,get_colorsasgcparser=ColorizingArgumentParser(description="This is a simple example of a ColorizingArgumentParser.",colors={'help':'LightCyan'})parser.add_argument('test1',action='store',help='Test 1')parser.add_argument('test2',action='store',help='Test 2')parser.add_argument('--optional-arg','-o',action='store',type=int,help='An optional integer')parser.add_argument('--verbose','-v',action='store_true',help='Increase verbosity.')args=parser.parse_args()logger=get_logger('My Logger',level_names={log21.DEBUG:' ? ',log21.INFO:' + ',log21.WARNING:' ! ',log21.ERROR:'!!!'})ifargs.verbose:logger.setLevel(log21.DEBUG)else:logger.setLevel(log21.INFO)logger.debug(gc('LightBlue')+'Verbose mode on!')logger.debug('Arguments:\n''\tTest 1:%s\n''\tTest 2:%s\n''\tOptional:%s',args=(args.test1,args.test2,args.optional_arg))logger.info(gc('LightGreen')+args.test1)logger.info(gc('LightWhite')+'Done!')Pretty-Printing and Tree-Printingimportjsonimportlog21data=json.load(open('json.json','r'))# Prints data using python's built-in print functionprint(data)# Uses `log21.pprint` to print the datalog21.pprint(data)# Uses `log21.tree_print` to print the datalog21.tree_print(data)Logging Windowimportlog21window=log21.get_logging_window('My Logging Window',width=80)window.font=('Courier New',9)# Basic loggingwindow.info('This is a basic logging message.')# Using ANSI and HEX colors# List of ANSI colors: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors# ANSI color format: \033[<attribute>mwindow.info('\033[91mThis is RED message.')window.info('\033[102mThis is message with GREEN background.')# HEX color format: \033#<HEX-COLOR>hf (where f represents the foreground color) and# \033#<HEX-COLOR>hb (where b represents the background color)window.info('\x1b#009900hbThis is a text with GREEN background.')window.info('\033#0000FFhf\033[103mThis is message with BLUE foreground and YELLOW background.')importrandom,string# And here is a text with random colorstext='I have random colors XD'colored_text=''forcharacterintext:color='\033#'+''.join(random.choice(string.hexdigits)for_inrange(6))+'hf'colored_text+=color+characterwindow.error(colored_text)# See more examples in# https://github.com/MPCodeWriter21/log21/blob/066efc1e72542531012d36974bbf6cd4c5941378/log21/LoggingWindow.py#L155# and# https://github.com/MPCodeWriter21/log21/blob/066efc1e72542531012d36974bbf6cd4c5941378/log21/__init__.py#L144ProgressBar# Example 1importlog21,time# Define a very simple log21 progress barprogress_bar=log21.ProgressBar()# And here is a simple loop that will print the progress barforiinrange(100):progress_bar(i+1,100)time.sleep(0.08)# Example 2importtime,randomfromlog21importProgressBar,get_colorsasgc# Let's customize the progress bar a little bit this timeprogress_bar=ProgressBar(width=50,fill='#',empty='-',prefix='[',suffix=']',colors={'progress in-progress':gc('Bright Red'),'progress complete':gc('Bright Cyan'),'percentage in-progress':gc('Green'),'percentage complete':gc('Bright Cyan'),'prefix-color in-progress':gc('Bright White'),'prefix-color complete':gc('Bright White'),'prefix-color failed':gc('Bright White'),'suffix-color in-progress':gc('Bright White'),'suffix-color complete':gc('Bright White'),'suffix-color failed':gc('Bright White')})foriinrange(84):progress_bar(i+1,84)time.sleep(random.uniform(0.05,0.21))Argumentify (Check outthe manual way)# Common Sectionimportlog21classReversedText:def__init__(self,text:str):self._text=text[::-1]def__str__(self):returnself._textdef__repr__(self):returnf"<{self.__class__.__name__}(text='{self._text}') at{hex(id(self))}>"# Old waydefmain():"""Here is my main function"""parser=log21.ColorizingArgumentParser()parser.add_argument('--positional-arg','-p',action='store',type=int,required=True,help="This argument is positional!")parser.add_argument('--optional-arg','-o',action='store',type=ReversedText,help="Whatever you pass here will be REVERSED!")parser.add_argument('--arg-with-default','-a',action='store',default=21,help="The default value is 21")parser.add_argument('--additional-arg','-A',action='store',help="This one is extra.")parser.add_argument('--verbose','-v',action='store_true',help="Increase verbosity")args=parser.parse_args()ifargs.verbose:log21.basic_config(level='DEBUG')log21.info(f"positional_arg ={args.positional_arg}")log21.info(f"optional_arg ={args.optional_arg}")log21.debug(f"arg_with_default ={args.arg_with_default}")log21.debug(f"additional_arg ={args.additional_arg}")if__name__=='__main__':main()# New waydefmain(positional_arg:int,/,optional_arg:ReversedText,arg_with_default:int=21,additional_arg=None,verbose:bool=False):"""Some description:param positional_arg: This argument is positional!:param optional_arg: Whatever you pass here will be REVERSED!:param arg_with_default: The default value is 21:param additional_arg: This one is extra.:param verbose: Increase verbosity"""ifverbose:log21.basic_config(level='DEBUG')log21.info(f"{positional_arg= }")log21.info(f"{optional_arg= !s}")log21.debug(f"{arg_with_default= }")log21.debug(f"{additional_arg= !s}")if__name__=='__main__':log21.argumentify(main)Example with multiple functions as entry-point:importastimportoperatorfromfunctoolsimportreduceimportlog21# `safe_eval` Based on https://stackoverflow.com/a/9558001/1113207# Supported Operatorsoperators={ast.Add:operator.add,ast.Sub:operator.sub,ast.Mult:operator.mul,ast.Div:operator.truediv,ast.FloorDiv:operator.floordiv,ast.Pow:operator.pow,ast.BitXor:operator.xor,ast.USub:operator.neg}defsafe_eval(expr:str):"""Safely evaluate a mathematical expression.>>> eval_expr('2^6')4>>> eval_expr('2**6')64>>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')-5.0:param expr: expression to evaluate:raises SyntaxError: on invalid expression:return: result of the evaluation"""try:return_eval(ast.parse(expr,mode='eval').body)except(TypeError,KeyError,SyntaxError):log21.error(f'Invalid expression:{expr}')raisedef_eval(node:ast.AST):"""Internal implementation of `safe_eval`.:param node: AST node to evaluate:raises TypeError: on invalid node:raises KeyError: on invalid operator:raises ZeroDivisionError: on division by zero:raises ValueError: on invalid literal:raises SyntaxError: on invalid syntax:return: result of the evaluation"""ifisinstance(node,ast.Num):# <number>returnnode.nifisinstance(node,ast.BinOp):# <left> <operator> <right>returnoperators[type(node.op)](_eval(node.left),_eval(node.right))ifisinstance(node,ast.UnaryOp):# <operator> <operand> e.g., -1returnoperators[type(node.op)](_eval(node.operand))raiseTypeError(node)# Example codedefaddition(*numbers:float):"""Addition of numbers.Args:numbers (float): numbers to add"""iflen(numbers)<2:log21.error('At least two numbers are required! Use `-n`.')returnlog21.info(f'Result:{sum(numbers)}')defmultiplication(*numbers:float):"""Multiplication of numbers.Args:numbers (float): numbers to multiply"""iflen(numbers)<2:log21.error('At least two numbers are required! Use `-n`.')returnlog21.info(f'Result:{reduce(lambdax,y:x*y,numbers)}')defcalc(*inputs:str,verbose:bool=False):"""Calculate numbers.:param inputs: numbers and operators"""expression=' '.join(inputs)iflen(expression)<3:log21.error('At least two numbers and one operator are required! Use `-i`.')returnifverbose:log21.basic_config(level='DEBUG')log21.debug(f'Expression:{expression}')try:log21.info(f'Result:{safe_eval(expression)}')except(TypeError,KeyError,SyntaxError):passif__name__=="__main__":log21.argumentify({'add':addition,'mul':multiplication,'calc':calc})AboutAuthor: CodeWriter21 (Mehrad Pooryoussof)GitHub:MPCodeWriter21Telegram Channel:@CodeWriter21Aparat Channel:CodeWriter21Licenseapache-2.0DonateIn order to support this project you can donate some crypto of your choice 8DDonate AddressesOr if you can't, givethis projecta star on GitHub :)ReferencesANSI Color Codes (
Wikipedia):https://en.wikipedia.org/wiki/ANSI_escape_code