gitman.common   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 126
dl 0
loc 185
ccs 107
cts 107
cp 1
rs 9.84
c 0
b 0
f 0
wmc 32

3 Methods

Rating   Name   Duplication   Size   Complexity  
A WarningFormatter.format() 0 7 2
A WarningFormatter.__init__() 0 4 1
A WideHelpFormatter.__init__() 0 3 1

7 Functions

Rating   Name   Duplication   Size   Complexity  
A positive_int() 0 5 2
A newline() 0 3 1
A indent() 0 3 1
A dedent() 0 6 2
B configure_logging() 0 44 7
B show() 0 23 8
B style() 0 17 7
1
"""Common exceptions, classes, and functions."""
2
3 1
import argparse
4 1
import logging
5 1
import os
6 1
import sys
7
8 1
import log
9
10
from . import settings
11 1
12
13
class WideHelpFormatter(argparse.HelpFormatter):
14 1
    """Command-line help text formatter with wider help text."""
15
16
    def __init__(self, *args, **kwargs):
17 1
        kwargs['max_help_position'] = 40
18 1
        super().__init__(*args, **kwargs)
19
20
21 1
class WarningFormatter(logging.Formatter):
22
    """Logging formatter that displays verbose formatting for WARNING+."""
23
24 1
    def __init__(self, default_format, verbose_format, *args, **kwargs):
25 1
        super().__init__(*args, **kwargs)
26 1
        self.default_format = default_format
27 1
        self.verbose_format = verbose_format
28
29 1
    def format(self, record):
30
        # pylint: disable=protected-access
31
        if record.levelno > log.INFO:
32 1
            self._style._fmt = self.verbose_format
33 1
        else:
34
            self._style._fmt = self.default_format
35 1
        return super().format(record)
36 1
37
38
def positive_int(value):
39 1
    value = int(value)
40
    if value < 1:
41 1
        raise TypeError
42 1
    return value
43 1
44 1
45
class _Config:
46
    """Share logging options."""
47 1
48
    MAX_VERBOSITY = 4
49
50 1
    verbosity = 0
51
    indent_level = 0
52 1
53 1
54
def configure_logging(count=0):
55
    """Configure logging using the provided verbosity count."""
56 1
    if count == -1:
57
        level = settings.QUIET_LOGGING_LEVEL
58 1
        default_format = settings.DEFAULT_LOGGING_FORMAT
59 1
        verbose_format = settings.LEVELED_LOGGING_FORMAT
60 1
    elif count == 0:
61 1
        level = settings.DEFAULT_LOGGING_LEVEL
62 1
        default_format = settings.DEFAULT_LOGGING_FORMAT
63 1
        verbose_format = settings.LEVELED_LOGGING_FORMAT
64 1
    elif count == 1:
65 1
        level = settings.VERBOSE_LOGGING_LEVEL
66 1
        default_format = settings.VERBOSE_LOGGING_FORMAT
67 1
        verbose_format = settings.VERBOSE_LOGGING_FORMAT
68 1
    elif count == 2:
69 1
        level = settings.VERBOSE2_LOGGING_LEVEL
70 1
        default_format = settings.VERBOSE_LOGGING_FORMAT
71 1
        verbose_format = settings.VERBOSE_LOGGING_FORMAT
72 1
    elif count == 3:
73 1
        level = settings.VERBOSE2_LOGGING_LEVEL
74 1
        default_format = settings.VERBOSE2_LOGGING_FORMAT
75 1
        verbose_format = settings.VERBOSE2_LOGGING_FORMAT
76 1
    else:
77 1
        level = settings.VERBOSE2_LOGGING_LEVEL - 1
78
        default_format = settings.VERBOSE2_LOGGING_FORMAT
79 1
        verbose_format = settings.VERBOSE2_LOGGING_FORMAT
80 1
81 1
    # Set a custom formatter
82
    log.reset()
83
    log.init(level=level)
84 1
    log.silence('datafiles', allow_warning=True)
85 1
    logging.captureWarnings(True)
86 1
    formatter = WarningFormatter(
87
        default_format, verbose_format, datefmt=settings.LOGGING_DATEFMT
88 1
    )
89 1
    logging.root.handlers[0].setFormatter(formatter)
90
91
    # Warn about excessive verbosity
92 1
    if count > _Config.MAX_VERBOSITY:
93 1
        msg = "Maximum verbosity level is {}".format(_Config.MAX_VERBOSITY)
94 1
        log.warning(msg)
95 1
        _Config.verbosity = _Config.MAX_VERBOSITY
96
    else:
97 1
        _Config.verbosity = count
98
99
100 1
def indent():
101
    """Increase the indent of future output lines."""
102 1
    _Config.indent_level += 1
103
104
105 1
def dedent(level=None):
106
    """Decrease (or reset) the indent of future output lines."""
107 1
    if level is None:
108 1
        _Config.indent_level = max(0, _Config.indent_level - 1)
109
    else:
110 1
        _Config.indent_level = level
111
112
113 1
def newline():
114
    """Write a new line to standard output."""
115 1
    show("")
116
117
118 1
def show(
119
    *messages,
120 1
    file=sys.stdout,
121 1
    log=log,  # pylint: disable=redefined-outer-name
122
    **kwargs,
123 1
):
124
    """Write to standard output or error if enabled."""
125 1
    if any(messages):
126 1
        assert 'color' in kwargs, "Color is required"
127 1
128 1
    color = kwargs.pop('color', None)
129 1
130 1
    for message in messages:
131 1
        if _Config.verbosity == 0:
132 1
            text = ' ' * 2 * _Config.indent_level + style(message, color)
133 1
            print(text, file=file)
134
        elif _Config.verbosity >= 1:
135 1
            message = message.strip()
136
            if message and log:
137
                if color == 'error':
138 1
                    log.error(message)
139 1
                else:
140 1
                    log.info(message)
141 1
142 1
143 1
BOLD = '\033[1m'
144 1
RED = '\033[31m'
145 1
GREEN = '\033[32m'
146 1
YELLOW = '\033[33m'
147
BLUE = '\033[34m'
148 1
MAGENTA = '\033[35m'
149
CYAN = '\033[36m'
150
WHITE = '\033[37m'
151
RESET = '\033[0m'
152
153
COLORS = dict(
154
    path='',
155
    git_rev=BOLD + BLUE,
156
    git_dirty=BOLD + MAGENTA,
157
    git_changes=YELLOW,
158
    shell=BOLD + GREEN,
159
    shell_info=BOLD + MAGENTA,
160
    shell_output=CYAN,
161
    shell_error=YELLOW,
162
    message=BOLD + WHITE,
163 1
    success=BOLD + GREEN,
164 1
    error=BOLD + RED,
165 1
)
166 1
167 1
168
def style(msg, name=None, *, _color_support=False):
169 1
    is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
170 1
    supports_ansi = sys.platform != 'win32' or 'ANSICON' in os.environ
171
    if not (is_tty and supports_ansi) and not _color_support:
172 1
        return msg
173 1
174 1
    if name == 'shell':
175
        return msg.replace("$ ", COLORS[name] + "$ " + RESET)
176 1
177 1
    color = COLORS.get(name)
178
    if color:
179
        return color + msg + RESET
180 1
181
    if msg:
182
        assert color is not None, "Unknown style name requested: {!r}".format(name)
183
184
    return msg
185