Passed
Push — develop ( 4d6495...2dddb7 )
by Jace
03:19
created

gitman.common   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 121
dl 0
loc 179
ccs 106
cts 106
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 2 1

7 Functions

Rating   Name   Duplication   Size   Complexity  
A newline() 0 3 1
B configure_logging() 0 42 7
B show() 0 18 8
B style() 0 18 7
A positive_int() 0 5 2
A indent() 0 3 1
A dedent() 0 6 2
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
from . import settings
9
10
11 1
_log = logging.getLogger(__name__)
12
13
14 1
class WideHelpFormatter(argparse.HelpFormatter):
15
    """Command-line help text formatter with wider help text."""
16
17 1
    def __init__(self, *args, **kwargs):
18 1
        super().__init__(*args, max_help_position=40, **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 > logging.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
    logging.basicConfig(level=level)
83
    logging.captureWarnings(True)
84 1
    formatter = WarningFormatter(default_format, verbose_format,
85 1
                                 datefmt=settings.LOGGING_DATEFMT)
86 1
    logging.root.handlers[0].setFormatter(formatter)
87
    logging.getLogger('yorm').setLevel(max(level, settings.YORM_LOGGING_LEVEL))
88 1
89 1
    # Warn about excessive verbosity
90
    if count > _Config.MAX_VERBOSITY:
91
        msg = "Maximum verbosity level is {}".format(_Config.MAX_VERBOSITY)
92 1
        logging.warning(msg)
93 1
        _Config.verbosity = _Config.MAX_VERBOSITY
94 1
    else:
95 1
        _Config.verbosity = count
96
97 1
98
def indent():
99
    """Increase the indent of future output lines."""
100 1
    _Config.indent_level += 1
101
102 1
103
def dedent(level=None):
104
    """Decrease (or reset) the indent of future output lines."""
105 1
    if level is None:
106
        _Config.indent_level = max(0, _Config.indent_level - 1)
107 1
    else:
108 1
        _Config.indent_level = level
109
110 1
111
def newline():
112
    """Write a new line to standard output."""
113 1
    show("")
114
115 1
116
def show(*messages, file=sys.stdout, log=_log, **kwargs):
117
    """Write to standard output or error if enabled."""
118 1
    if any(messages):
119
        assert 'color' in kwargs, "Color is required"
120 1
121 1
    color = kwargs.pop('color', None)
122
123 1
    for message in messages:
124
        if _Config.verbosity == 0:
125 1
            text = ' ' * 2 * _Config.indent_level + style(message, color)
126 1
            print(text, file=file)
127 1
        elif _Config.verbosity >= 1:
128 1
            message = message.strip()
129 1
            if message and log:
130 1
                if color == 'error':
131 1
                    log.error(message)
132 1
                else:
133 1
                    log.info(message)
134
135 1
136
BOLD = '\033[1m'
137
RED = '\033[31m'
138 1
GREEN = '\033[32m'
139 1
YELLOW = '\033[33m'
140 1
BLUE = '\033[34m'
141 1
MAGENTA = '\033[35m'
142 1
CYAN = '\033[36m'
143 1
WHITE = '\033[37m'
144 1
RESET = '\033[0m'
145 1
146 1
COLORS = dict(
147
    path='',
148 1
    git_rev=BOLD + BLUE,
149
    git_dirty=BOLD + MAGENTA,
150
    git_changes=YELLOW,
151
    shell=BOLD + GREEN,
152
    shell_info=BOLD + MAGENTA,
153
    shell_output=CYAN,
154
    shell_error=YELLOW,
155
    message=BOLD + WHITE,
156
    success=BOLD + GREEN,
157
    error=BOLD + RED,
158
)
159
160
161
def style(msg, name=None, *, _color_support=False):
162
    is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
163 1
    supports_ansi = sys.platform != 'win32' or 'ANSICON' in os.environ
164 1
    if not (is_tty and supports_ansi) and not _color_support:
165 1
        return msg
166 1
167 1
    if name == 'shell':
168
        return msg.replace("$ ", COLORS.get(name) + "$ " + RESET)
169 1
170 1
    color = COLORS.get(name)
171
    if color:
172 1
        return color + msg + RESET
173 1
174 1
    if msg:
175
        assert color is not None, \
176 1
            "Unknown style name requested: {!r}".format(name)
177 1
178
    return msg
179