Passed
Pull Request — develop (#571)
by
unknown
04:11
created

doorstop.gui.main._log()   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 15
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 11
dl 15
loc 15
rs 9.85
c 0
b 0
f 0
cc 3
nop 1
1
#!/usr/bin/env python
2
# SPDX-License-Identifier: LGPL-3.0-only
3
# type: ignore
4
# pylint: disable=import-outside-toplevel
5
6
"""Graphical interface for Doorstop."""
7
8
import argparse
9
import logging
10
import os
11
import sys
12
from unittest.mock import Mock
13
14
from doorstop import common, settings
15
from doorstop.common import HelpFormatter, WarningFormatter
16
from doorstop.gui import application, widget
17
18
try:
19
    import tkinter as tk
20
    from tkinter import ttk
21
except ImportError as _exc:
22
    sys.stderr.write("WARNING: {}\n".format(_exc))
23
    tk = Mock()
24
    ttk = Mock()
25
26
27
log = common.logger(__name__)
28
29
30
def main(args=None):
31
    """Process command-line arguments and run the program."""
32
    from doorstop import GUI, VERSION
33
34
    # Shared options
35
    debug = argparse.ArgumentParser(add_help=False)
36
    debug.add_argument("-V", "--version", action="version", version=VERSION)
37
    debug.add_argument(
38
        "-v", "--verbose", action="count", default=0, help="enable verbose logging"
39
    )
40
    shared = {"formatter_class": HelpFormatter, "parents": [debug]}
41
    parser = argparse.ArgumentParser(prog=GUI, description=__doc__, **shared)
42
43
    # Build main parser
44
    parser.add_argument(
45
        "-j", "--project", metavar="PATH", help="path to the root of the project"
46
    )
47
48
    # Parse arguments
49
    args = parser.parse_args(args=args)
50
51
    # Configure logging
52
    _configure_logging(args.verbose)
53
54
    # Run the program
55
    try:
56
        success = run(args, os.getcwd(), parser.error)
57
    except KeyboardInterrupt:
58
        log.debug("program interrupted")
59
        success = False
60
    if success:
61
        log.debug("program exited")
62
        return 0
63
    else:
64
        log.debug("program exited with error")
65
        return 1
66
67
68
def _configure_logging(verbosity=0):
69
    """Configure logging using the provided verbosity level (0+)."""
70
    # Configure the logging level and format
71
    if verbosity == 0:
72
        level = settings.VERBOSE_LOGGING_LEVEL
73
        default_format = settings.VERBOSE_LOGGING_FORMAT
74
        verbose_format = settings.VERBOSE_LOGGING_FORMAT
75
    elif verbosity == 1:
76
        level = settings.VERBOSE2_LOGGING_LEVEL
77
        default_format = settings.VERBOSE_LOGGING_FORMAT
78
        verbose_format = settings.VERBOSE_LOGGING_FORMAT
79
    else:
80
        level = settings.VERBOSE2_LOGGING_LEVEL
81
        default_format = settings.TIMED_LOGGING_FORMAT
82
        verbose_format = settings.TIMED_LOGGING_FORMAT
83
84
    # Set a custom formatter
85
    logging.basicConfig(level=level)
86
    formatter = WarningFormatter(default_format, verbose_format)
87
    logging.root.handlers[0].setFormatter(formatter)
88
89
90
def run(args, cwd, error):
91
    """Start the GUI.
92
93
    :param args: Namespace of CLI arguments (from this module or the CLI)
94
    :param cwd: current working directory
95
    :param error: function to call for CLI errors
96
97
    """
98
    from doorstop import __project__, __version__
99
100
    # Exit if tkinter is not available
101
    if isinstance(tk, Mock) or isinstance(ttk, Mock):
102
        return error("tkinter is not available")
103
104
    else:
105
106
        root = widget.Tk()
107
        root.title("{} ({})".format(__project__, __version__))
108
109
        from sys import platform as _platform
110
111
        from doorstop.gui import resources
112
113
        # Load the icon
114
        if _platform in ("linux", "linux2", "darwin"):
115
            # Linux
116
            root.tk.call(
117
                # pylint: disable=protected-access
118
                "wm",
119
                "iconphoto",
120
                root._w,
121
                tk.PhotoImage(data=resources.b64_doorstopicon_png),
122
            )
123
        elif _platform in ("win32", "win64"):
124
            # Windows
125
            import base64
126
            import tempfile
127
128
            try:
129
                with tempfile.TemporaryFile(
130
                    mode="w+b", suffix=".ico", delete=False
131
                ) as theTempIconFile:
132
                    theTempIconFile.write(
133
                        base64.b64decode(resources.b64_doorstopicon_ico)
134
                    )
135
                    theTempIconFile.flush()
136
                root.iconbitmap(theTempIconFile.name)
137
            finally:
138
                try:
139
                    os.unlink(theTempIconFile.name)
140
                except Exception:  # pylint: disable=W0703
141
                    pass
142
143
        app = application.Application(root, cwd, args.project)
144
145
        root.update()
146
        root.minsize(root.winfo_width(), root.winfo_height())
147
        app.mainloop()
148
149
        return True
150
151
152
if __name__ == "__main__":
153
    sys.exit(main())
154