"Loris Bennett" <loris.benn...@fu-berlin.de> writes: > dn <pythonl...@danceswithmice.info> writes: > >> On 01/04/2023 02.01, Loris Bennett wrote: >>> Hi, >>> In my top level program file, main.py, I have >>> def main_function(): >>> parser = argparse.ArgumentParser(description="my prog") >>> ... >>> args = parser.parse_args() >>> config = configparser.ConfigParser() >>> if args.config_file is None: >>> config_file = DEFAULT_CONFIG_FILE >>> else: >>> config_file = args.config_file >>> config.read(config_file) >>> logging.config.fileConfig(fname=config_file) >>> logger = logging.getLogger(__name__) >>> do_some_stuff() >>> my_class_instance = myprog.MyClass() >>> def do_some_stuff(): >>> logger.info("Doing stuff") >>> This does not work, because 'logger' is not known in the function >>> 'do_some_stuff'. >>> However, if in 'my_prog/my_class.py' I have >>> class MyClass: >>> def __init__(self): >>> logger.debug("created instance of MyClass") >>> this 'just works'. >>> I can add >>> logger = logging.getLogger(__name__) >>> to 'do_some_stuff', but why is this necessary in this case but not >>> in >>> the class? >>> Or should I be doing this entirely differently? >> >> Yes: differently. >> >> To complement @Peter's response, two items for consideration: >> >> 1 once main_function() has completed, have it return logger and other >> such values/constructs. The target-identifiers on the LHS of the >> function-call will thus be within the global scope. >> >> 2 if the purposes of main_function() are condensed-down to a few >> (English, or ..., language) phrases, the word "and" will feature, eg >> - configure env according to cmdLN args, >> - establish log(s), >> - do_some_stuff(), ** AND ** >> - instantiate MyClass. >> >> If these (and do_some_stuff(), like MyClass' methods) were split into >> separate functions* might you find it easier to see them as separate >> sub-solutions? Each sub-solution would be able to contribute to the >> whole - the earlier ones as creating (outputting) a description, >> constraint, or basis; which becomes input to a later function/method. > > So if I want to modify the logging via the command line I might have the > following: > > --------------------------------------------------------------------- > > #!/usr/bin/env python3 > > import argparse > import logging > > > def get_logger(log_level): > """Get global logger""" > > logger = logging.getLogger('example') > logger.setLevel(log_level) > ch = logging.StreamHandler() > formatter = logging.Formatter('%(levelname)s - %(message)s') > ch.setFormatter(formatter) > logger.addHandler(ch) > > return logger > > > def do_stuff(): > """Do some stuff""" > > # logger.info("Doing stuff!")
Looks like I just need logger = logging.getLogger('example) logger.info("Doing stuff!") > > def main(): > """Main""" > > parser = argparse.ArgumentParser() > parser.add_argument("--log-level", dest="log_level", type=int) > args = parser.parse_args() > > print(f"log level: {args.log_level}") > > logger = get_logger(args.log_level) > logger.debug("Logger!") > do_stuff() > > > if __name__ == "__main__": > main() > > --------------------------------------------------------------------- > > How can I get logging for 'do_stuff' in this case without explicitly > passing 'logger' as an argument or using 'global'? > > Somehow I am failing to understand how to get 'logger' defined > sufficiently high up in the program that all references 'lower down' in > the program will be automatically resolved. > >> * there is some debate amongst developers about whether "one function, >> one purpose" should be a rule, a convention, or tossed in the >> trash. YMMV! >> >> Personal view: SOLID's "Single" principle applies: there should be >> only one reason (hanging over the head of each method/function, like >> the Sword of Damocles) for it to change - or one 'user' who could >> demand a change to that function. In other words, an updated cmdLN >> option shouldn't affect a function which establishes logging, for >> example. >> >> >> Web.Refs: >> https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf >> https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin >> https://idioms.thefreedictionary.com/sword+of+Damocles >> https://en.wikipedia.org/wiki/Damocles > > I don't really get the "one reason" idea and the Sword of Damocles > analogy. The later to me is more like "there's always a downside", > since the perks of being king may mean someone might try to usurp the > throne and kill you. Where is the "single principle" aspect? > > However, the idea of "one responsibility" in the sense of "do only one > thing" seems relatively clear, especially if I think in terms of writing > unit tests. > > Cheers, > > Loris -- Dr. Loris Bennett (Herr/Mr) ZEDAT, Freie Universität Berlin -- https://mail.python.org/mailman/listinfo/python-list