As you can see on my blog, I write in Python (3) a lot. I struggled with several things when I had been writing the scripts and small modules. Here is what I basically needed:

  1. Handling the output in logging like manner. That means to have ability to set up logging level (different for debug, info, or silent mode). This should be scalable so I can use this logging settings in several modules with minimal code needed.
  2. Parsing command line arguments
  3. logging should be set by reading the logging config file
  4. have a possibility to turn on/off debug mode easily
  5. have a possibility to terminate process by CTRL+C nicely
  6. Nice layout of code and readability (for maintenance). In the best, everything wrapped in functions and objects. Not something like this:
# beginning of my file

print("Hello. This is on the beginning of the file")

from argparse import ArgumentParser
# some stuffs happens here

def some_func():
    # doing something
    pass

class SomeObject():
    # object from hell
    pass

# ...

if __name__ == "__main__":
    ob = SomeObject()
    res = some_func(ob)
```python

code above just seems painful to handle. My final layout of these files is as follows:

-   one main file, sometimes called `main.py` or `program_name.py`. This is what is being ran when starting the program.
-   importing `logging` module at the beginning of the main file (this is only code which is not wrapped). It's necessary because I want to have logger available from the beginning. Then simply getting the main logger in every app.
-   in `if __name__ == "__main__"` I call `main()` method.
-   argument parsing happens in `argument_parsing()` method in `main()` and returns `args` object. `args` object is not going anywhere else then in `main()` method. If I need things from `args` object, I just pass them as arguments to the methods or classes constructors. This helps to leave the code clean and easy to debug.
-   if a program needs more than one class, I usually split it to several modules.
-   methods is usually better to wrap under some class
-   in arguments, I almost always add `--debug` flag which turns logging to `DEBUG` level.

So here is an example:

```language-python
"""
Docstring describing the whole progam
"""

import logging
from logging.config import fileConfig

fileConfig('logging_config.ini')
log = logging.getLogger()

class MainProgramObject():

    def __init__(self, arg1, arg2):
        log.debug("Initilizing object.")
        self.arg1 = arg1
        self.arg2 = arg2

    def some_logic(self, ):
        log.info("I'm doing nasty stuffs from module another_module.py")

        from another_module import DidIt
        dit = DidIt(self.arg1)

        return dit.get_result()


def parse_arguments():
    from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

    parser = ArgumentParser(description="Brief description of program", formatter_class=ArgumentDefaultsHelpFormatter)
    parser.add_argument( "-a", "--arg1", type=int, default = "HiHi", help = "First argument!")
    parser.add_argument( "-b", "--barg2", type=str, default = "HeHe", help = "Second argument!")
    parser.add_argument( "-d", "--debug", action="store_true", help = "Turn on debug mode." )

    args = parser.parse_args()
    return args

def main():

    args = parse_arguments()
    if args.debug:
        log.setLevel(logging.DEBUG)
    log.debug("Log level set to {}".format(log.level))

    try:
        mainObj = MainProgramObject(args.arg1, args.barg2)
        result = mainObj.some_logic()
        print result
    except KeyboardInterrupt as ex:
        log.warning("Termined by user.")

if __name__ == "__main__":
    main()
```python

an example of `another_module.py` might look like this:

```language-python
"""
Again, describe what is going here
"""

import logging
log = logging.getLogger(__name__)

class DidIt():
    def __init__(self, argums):
        log.debug("Working on this arg {}".format(self.argums))
        self.argums = argums

    def get_result(self):
        # example of doing some stuffs
        return type(self.argums)
```python

This is the best workflow I've found as far. But there of course might be better ways ;) .

And the `logging_config.ini` looks like this:

```language-python
[loggers]
keys=root

[handlers]
keys=stream_handler

[formatters]
keys=formatter

[logger_root]
level=INFO
handlers=stream_handler

[handler_stream_handler]
class=StreamHandler
level=DEBUG
formatter=formatter
args=(sys.stderr,)

[formatter_formatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s