Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Disable multiple help across files #35

Open
Kristinita opened this issue Jan 6, 2018 · 5 comments
Open

[Question] Disable multiple help across files #35

Kristinita opened this issue Jan 6, 2018 · 5 comments
Labels

Comments

@Kristinita
Copy link

1. Briefly

I don't understand, how I can disable multiple help, if my program contains multiple files.

2. Configuration

For example, I have a folder with 4 files:

import logbook
import sys

log = logbook.Logger("Sasha Logbook")


def clize_log_level(*, logbook_level: 'll'="NOTICE"):
    """Change log levels via command line.

    User select, which logging messages to see. See about 6 log levels here:
    https://logbook.readthedocs.io/en/stable/quickstart.html

    :param logbook_level: user select logging level
    """
    if logbook_level == "DEBUG":
        logbook.StreamHandler(sys.stdout,
                              level=logbook.DEBUG).push_application()
    elif logbook_level == "ERROR":
        logbook.StreamHandler(sys.stdout,
                              level=logbook.ERROR).push_application()
    else:
        logbook.StreamHandler(sys.stdout,
                              level=logbook.NOTICE).push_application()
  • first_test.py:
from clize import run
from config import clize_log_level
from config import log

run(clize_log_level, exit=False)

log.debug("First test + debug message")
log.notice("First test + notice message")
log.error("First test + error message")


first_test_variable = True
  • second_test.py:
from clize import run
from config import clize_log_level
from config import log

run(clize_log_level, exit=False)

log.debug("Second test + debug message")
log.notice("Second test + notice message")
log.error("Second test + error message")


second_test_variable = True
  • run_tests.py:
from clize import run
from config import clize_log_level
from config import log
from first_test import first_test_variable
from second_test import second_test_variable

if first_test_variable and second_test_variable is True:
    log.debug("Run tests + debug message")
    log.notice("Run tests + notice message")
    log.error("Run tests + error message")

3. Behavior of the program

If I run run_tests.py, run first_test.py and second_test.py. Logging messages from first_test.py and second_test.py return.

The program works as expected:

D:\SashaClize>python run_tests.py --ll=DEBUG
[2018-01-06 15:21:38.251565] DEBUG: Sasha Logbook: First test + debug message
[2018-01-06 15:21:38.251565] NOTICE: Sasha Logbook: First test + notice message
[2018-01-06 15:21:38.251565] ERROR: Sasha Logbook: First test + error message
[2018-01-06 15:21:38.252565] DEBUG: Sasha Logbook: Second test + debug message
[2018-01-06 15:21:38.253197] NOTICE: Sasha Logbook: Second test + notice message
[2018-01-06 15:21:38.253332] ERROR: Sasha Logbook: Second test + error message
[2018-01-06 15:21:38.253457] DEBUG: Sasha Logbook: Run tests + debug message
[2018-01-06 15:21:38.253556] NOTICE: Sasha Logbook: Run tests + notice message
[2018-01-06 15:21:38.253556] ERROR: Sasha Logbook: Run tests + error message
D:\SashaClize>python run_tests.py --ll=ERROR
[2018-01-06 15:22:01.131626] ERROR: Sasha Logbook: First test + error message
[2018-01-06 15:22:01.132525] ERROR: Sasha Logbook: Second test + error message
[2018-01-06 15:22:01.133558] ERROR: Sasha Logbook: Run tests + error message

4. Problem

One problem: help menu show for me 2 times:

D:\SashaClize>python run_tests.py --help
Usage: run_tests.py [OPTIONS]

Change log levels via command line.

User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html

Options:
  --logbook-level, --ll=STR   user select logging level (default: NOTICE)

Other actions:
  -h, --help                  Show the help
Usage: run_tests.py [OPTIONS]

Change log levels via command line.

User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html

Options:
  --logbook-level, --ll=STR   user select logging level (default: NOTICE)

Other actions:
  -h, --help                  Show the help

If I have more <number>_test files, I have more help repeats.

How I need edit in my code, that don't see help multiple times?

Thanks.

@epsy epsy added the question label Jan 6, 2018
@epsy
Copy link
Owner

epsy commented Jan 6, 2018

You're calling run(clize_log_level, ...) once in each module, therefore arguments get interpreted twice. You can't notice it normally because your function does not product output of its own, but when you use --help, then the help is printed twice, because arguments were printed twice.

What you can do is move that call to run(clize_log_level., ...) into config.py. That way, because Python runs a module's code only once, your log-level setter will only run once.


Note that this is a highly unusual way to structure code for Python. Normally you would call clize.run(...) only in the module first executed by Python. You can do that by putting it into an if __name__ == '__main__' block like in the tutorial.

Your test logging code would go in a function of its own that you'd call after clize, e.g.:

def first_test():
    log.debug("First test + debug message")
    log.notice("First test + notice message")
    log.error("First test + error message")

if __name__ == '__main__':
    run(clize_log_level, exit=False)
    first_test()

You would do the same in run_tests.py, by importing the functions you created and running all three


In the future, you should look to avoid using exit=False: if there is an error in processing the parameters, the program would continue anyway.

This means making a way to have both the log-level setter and the "business" function be one function together. Fortunately you can pass functions as parameters in Python, e.g. set_log_level_then_call(first_test, loglevel='DEBUG'). The log level
You just have to hide this from clize so it can just worry about the loglevel parameter:

def set_loglevel_then_call_first(*args, **kwargs):
    set_log_level_then_call(first_test, *args, **kwargs)

Or alternatively: set_loglevel_then_call_first = functools.partial(set_log_level_then_call, first_test), which does the same.

Eventually you'll want to reverse the roles and make set_loglevel a decorator.

But for now I think you can ignore this last section :)

@Kristinita
Copy link
Author

Note that this is a highly unusual way to structure code for Python.

I'm sorry, is it correct structure? Code is working.

Structure:

D:.
│   body_check.py
│   config.py
│   run_tests.py
│   TextExample1.txt
│   TextExample2.txt

config.py:

"""Configuration.

Configuration for tests.

Variables:
    VERSION {str} -- version of module
    all_txt_in_eric_room_wihtout_subfolders {list(current_directory)} -- get all files in current directory
"""

import glob
import logbook
import sys

VERSION = "0.1"

# Get all .txt file in a directory
# https://stackoverflow.com/a/3964689/5951529
all_txt_in_eric_room_wihtout_subfolders = glob.glob('*.txt')


def version():
    """Show version.

    For details see:
    https://clize.readthedocs.io/en/stable/dispatching.html#alternate-actions
    """
    print(VERSION)


def v():
    """Alternative show version.

    For details see: https://github.com/epsy/clize/issues/34
    """
    print(VERSION)


def clize_log_level(*, logbook_level: 'll'="NOTICE"):
    """Change log levels via command line.

    User select, which logging messages to see. See about 6 log levels here:
    https://logbook.readthedocs.io/en/stable/quickstart.html

    :param logbook_level: user select logging level
    """
    if logbook_level == "DEBUG":
        logbook.StreamHandler(sys.stdout,
                              level=logbook.DEBUG).push_application()
    elif logbook_level == "NOTICE":
        logbook.StreamHandler(sys.stdout,
                              level=logbook.NOTICE).push_application()
    elif logbook_level == "ERROR":
        logbook.StreamHandler(sys.stdout,
                              level=logbook.ERROR).push_application()
    else:
        logbook.StreamHandler(sys.stdout,
                              level=logbook.NOTICE).push_application()

body_check.py:

"""Check files for body.

Check, contains files of current directory <body> or no.
"""

import logbook

from config import all_txt_in_eric_room_wihtout_subfolders

log = logbook.Logger("eric_body logbook")

body_test = True


def eric_body_function():
    """Check, contains body in a file, or no."""
    for filename in all_txt_in_eric_room_wihtout_subfolders:

        if "<body>" in open(filename).read():
            log.debug(filename + " contains <body>")
        else:
            log.error(
                "File " +
                filename +
                " not contain <body>.")
            global body_test
            body_test = False


def eric_body_summary():
    """Report, contains <body> in all files or no.

    Use flags, see https://stackoverflow.com/a/48052480/5951529
    """
    eric_body_function()
    if body_test is True:
        log.notice("All files contains <body>")
    else:
        log.error("Not all files contains <body>. Please, correct your files.")

run_tests.py:

"""Run tests.

Main file for running tests.
"""

import body_check
import logbook

from clize import run
from config import clize_log_level
from config import v
from config import version

log = logbook.Logger("run_tests logbook")


if __name__ == '__main__':
    run(clize_log_level, alt=[version, v], exit=False)
    body_check.eric_body_summary()


if body_check.body_test is True:
    log.notice("Success!")
else:
    log.error("Failure!")

TextExample1.txt:

Correct
<body>

TestExample2.txt:

Incorrect
<boty>

Thanks.

@Kristinita
Copy link
Author

I'm sorry for additional question. This is similar to foot in the door.

Thanks for the answer!

@epsy
Copy link
Owner

epsy commented Jan 20, 2018

Oh no. don't worry, I just had a busy week.


It looks like this would work correctly, good job on restructuring things into functions. Is there still an issue?

@epsy epsy reopened this Jan 20, 2018
@Kristinita
Copy link
Author

Is there still an issue?

See #37 . Otherwise my code works.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 participants