|
2 | 2 |
|
3 | 3 | """example is an example Python library and tool.
|
4 | 4 |
|
| 5 | +Divide one integer by another and log the result. Also log some information |
| 6 | +from an environment variable and a package resource. |
| 7 | +
|
| 8 | +EXIT STATUS |
| 9 | + This utility exits with one of the following values: |
| 10 | + 0 Calculation completed successfully. |
| 11 | + >0 An error occurred. |
| 12 | +
|
5 | 13 | Usage:
|
6 |
| - example [--log-level=LEVEL] |
| 14 | + example [--log-level=LEVEL] <dividend> <divisor> |
7 | 15 | example (-h | --help)
|
8 | 16 |
|
9 | 17 | Options:
|
10 | 18 | -h --help Show this message.
|
11 | 19 | --log-level=LEVEL If specified, then the log level will be set to
|
12 | 20 | the specified value. Valid values are "debug", "info",
|
13 |
| - "warning", "error", and "critical". [default: warning] |
| 21 | + "warning", "error", and "critical". [default: info] |
14 | 22 | """
|
15 | 23 |
|
16 | 24 | # Standard Python Libraries
|
|
21 | 29 | # Third-Party Libraries
|
22 | 30 | import docopt
|
23 | 31 | import pkg_resources
|
| 32 | +from schema import And, Schema, SchemaError, Use |
24 | 33 |
|
25 | 34 | from ._version import __version__
|
26 | 35 |
|
27 | 36 | DEFAULT_ECHO_MESSAGE = "Hello World from the example default!"
|
28 | 37 |
|
29 | 38 |
|
30 |
| -def example_div(x, y): |
| 39 | +def example_div(dividend, divisor): |
31 | 40 | """Print some logging messages."""
|
32 | 41 | logging.debug("This is a debug message")
|
33 | 42 | logging.info("This is an info message")
|
34 | 43 | logging.warning("This is a warning message")
|
35 | 44 | logging.error("This is an error message")
|
36 | 45 | logging.critical("This is a critical message")
|
37 |
| - return x / y |
| 46 | + return dividend / divisor |
38 | 47 |
|
39 | 48 |
|
40 | 49 | def main():
|
41 | 50 | """Set up logging and call the example function."""
|
42 | 51 | args = docopt.docopt(__doc__, version=__version__)
|
43 |
| - # Set up logging |
44 |
| - log_level = args["--log-level"] |
| 52 | + # Validate and convert arguments as needed |
| 53 | + schema = Schema( |
| 54 | + { |
| 55 | + "--log-level": And( |
| 56 | + str, |
| 57 | + Use(str.lower), |
| 58 | + lambda n: n in ("debug", "info", "warning", "error", "critical"), |
| 59 | + error="Possible values for --log-level are " |
| 60 | + + "debug, info, warning, error, and critical.", |
| 61 | + ), |
| 62 | + "<dividend>": Use(int, error="<dividend> must be an integer."), |
| 63 | + "<divisor>": And( |
| 64 | + Use(int), |
| 65 | + lambda n: n != 0, |
| 66 | + error="<divisor> must be an integer that is not 0.", |
| 67 | + ), |
| 68 | + str: object, # Don't care about other keys, if any |
| 69 | + } |
| 70 | + ) |
| 71 | + |
45 | 72 | try:
|
46 |
| - logging.basicConfig( |
47 |
| - format="%(asctime)-15s %(levelname)s %(message)s", level=log_level.upper() |
48 |
| - ) |
49 |
| - except ValueError: |
50 |
| - logging.critical( |
51 |
| - f'"{log_level}" is not a valid logging level. Possible values ' |
52 |
| - "are debug, info, warning, and error." |
53 |
| - ) |
| 73 | + args = schema.validate(args) |
| 74 | + except SchemaError as err: |
| 75 | + # Exit because one or more of the arguments were invalid |
| 76 | + print(err, file=sys.stderr) |
54 | 77 | return 1
|
55 | 78 |
|
56 |
| - print(f"8 / 2 == {example_div(8, 2)}") |
| 79 | + # Assign validated arguments to variables |
| 80 | + dividend = args["<dividend>"] |
| 81 | + divisor = args["<divisor>"] |
| 82 | + log_level = args["--log-level"] |
| 83 | + |
| 84 | + # Set up logging |
| 85 | + logging.basicConfig( |
| 86 | + format="%(asctime)-15s %(levelname)s %(message)s", level=log_level.upper() |
| 87 | + ) |
| 88 | + |
| 89 | + logging.info(f"{dividend} / {divisor} == {example_div(dividend, divisor)}") |
57 | 90 |
|
58 | 91 | # Access some data from an environment variable
|
59 | 92 | message = os.getenv("ECHO_MESSAGE", DEFAULT_ECHO_MESSAGE)
|
60 |
| - print(f'ECHO_MESSAGE="{message}"') |
| 93 | + logging.info(f'ECHO_MESSAGE="{message}"') |
61 | 94 |
|
62 | 95 | # Access some data from our package data (see the setup.py)
|
63 | 96 | secret_message = (
|
64 | 97 | pkg_resources.resource_string("example", "data/secret.txt")
|
65 | 98 | .decode("utf-8")
|
66 | 99 | .strip()
|
67 | 100 | )
|
68 |
| - print(f'Secret="{secret_message}"') |
| 101 | + logging.info(f'Secret="{secret_message}"') |
69 | 102 |
|
70 | 103 | # Stop logging and clean up
|
71 | 104 | logging.shutdown()
|
|
0 commit comments