Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass global debug flag variable throughout my code; should I use argparse?

Let's say I have a main program (test.py) and a little utilities program (test_utils.py) that has helper functions called by the main program. I would like to turn on debug statements in the code by passing a debug_flag boolean, which is read in via argparse.

Now I would like functions within my test_utils.py program to print debug statements as well, according to the value of debug_flag. I could always add debug_flag as a parameter to each function definition in test_utils.py and pass the parameter when the function is called, but is there a better way here, like make debug_flag a global variable? But if I do declare debug_flag to be global from test.py, how would that be imported into test_utils.py?

What would be the most elegant/Pythonic approach here?

test.py:

import argparse
from test_utils import summation

def main():
    args = get_args()
    debug_flag = True if args[debug] == 'True' else False
    print summation(5, 6, 7)

def get_args():
    parser = argparse.ArgumentParser(description='Test program')
    parser.add_argument('-d','--debug', help='Debug True/False', default=False)
    args = vars(parser.parse_args())
    return args

test_utils.py:

from test import debug_flag

def summation(x, y, z):
    if debug_flag:
        print 'I am going to add %s %s and %s' % (x, y, z)
    return x + y + z

EDIT1: To clarify - if I pass in the debug flag through argparse and thereby do set debug_flag to True - how would this be propagated to functions within test_utils.py?

EDIT2: Based on the suggestion by @joran-beasley, here's what I've got.

test.py:

import argparse
import logging
from test_utils import summation

def main():
    args = get_args()
    logging.getLogger("my_logger").setLevel(logging.DEBUG if args['debug'] == 'True' else logging.WARNING)
    print summation(5, 6, 7)

def get_args():
    parser = argparse.ArgumentParser(description='Test program')
    parser.add_argument('-d','--debug', help='Debug True/False', required=True)
    args = vars(parser.parse_args())
    return args

main()

test_utils.py

import logging

log = logging.getLogger('my_logger')

def summation(x, y, z):
    log.debug('I am going to add %s %s and %s' % (x, y, z))
    return x + y + z

When I run test.py, I get:

$ python test.py -d True
No handlers could be found for logger "my_logger"
18
like image 831
Craig Avatar asked Apr 11 '18 17:04

Craig


1 Answers

use logging

# this logger will always now be logging.DEBUG level
logging.getLogger("my_logger").setLevel(logging.DEBUG if args.debug else logging.WARNING)

then use

log = logging.getLogger("my_logger")
...
log.warn("some text that should always be seen!")
log.debug("some debug info!")

you can then do things where you have multiple levels of logging

log_level = logging.WARNING
if args.verbose > 0:
   log_level = logging.INFO
elif args.verbose > 3:
   log_level = logging.DEBUG

if for some reason you needed to retrieve the currentEffectiveLogLevel (you really shouldnt in most cases ... simply use log.debug when you want debug level output)

logging.getLogger("my_logger").getEffectiveLevel()

[edit to clarify]

log = logging.getLogger('my_logger')

def summation(x, y, z):
   log.debug('I am going to add %s %s and %s' % (x, y, z)) # will not print if my_logger does not have an effective level of debug
   return x + y + z

print(summation(2, 3, 4))
log.setLevel(logging.DEBUG)
print(summation(4, 5, 6))

or you can wrie a helper funtion

def is_debug():
    return logging.getLogger("my_logger").getEffectiveLevel() == logging.DEBUG

of coarse you can always do some horrible hacky crap also like writing it to a flat file and reading it in or using truly global variables (harder than you might think and lots of edge cases to worry about)

like image 87
Joran Beasley Avatar answered Nov 06 '22 07:11

Joran Beasley