]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | import logging |
d2e6a577 FG |
2 | import sys |
3 | ||
4 | ||
5 | class colorize(str): | |
6 | """ | |
7 | Pretty simple to use:: | |
8 | ||
9 | colorize.make('foo').bold | |
10 | colorize.make('foo').green | |
11 | colorize.make('foo').yellow | |
12 | colorize.make('foo').red | |
13 | colorize.make('foo').blue | |
14 | ||
15 | Otherwise you could go the long way (for example if you are | |
16 | testing this class):: | |
17 | ||
18 | string = colorize('foo') | |
19 | string._set_attributes() | |
20 | string.red | |
21 | ||
22 | """ | |
23 | ||
24 | def __init__(self, string): | |
25 | self.stdout = sys.__stdout__ | |
26 | self.appends = '' | |
27 | self.prepends = '' | |
28 | self.isatty = self.stdout.isatty() | |
29 | ||
30 | def _set_attributes(self): | |
31 | """ | |
32 | Sets the attributes here because the str class does not | |
33 | allow to pass in anything other than a string to the constructor | |
34 | so we can't really mess with the other attributes. | |
35 | """ | |
36 | for k, v in self.__colors__.items(): | |
37 | setattr(self, k, self.make_color(v)) | |
38 | ||
39 | def make_color(self, color): | |
40 | if not self.isatty: | |
41 | return self | |
42 | return color + self + '\033[0m' + self.appends | |
43 | ||
44 | @property | |
45 | def __colors__(self): | |
46 | return dict( | |
47 | blue='\033[34m', | |
48 | green='\033[92m', | |
49 | yellow='\033[33m', | |
50 | red='\033[91m', | |
51 | bold='\033[1m', | |
52 | ends='\033[0m' | |
53 | ) | |
54 | ||
55 | @classmethod | |
56 | def make(cls, string): | |
57 | """ | |
58 | A helper method to return itself and workaround the fact that | |
59 | the str object doesn't allow extra arguments passed in to the | |
60 | constructor | |
61 | """ | |
62 | obj = cls(string) | |
63 | obj._set_attributes() | |
64 | return obj | |
65 | ||
66 | # | |
67 | # Common string manipulations | |
68 | # | |
69 | yellow = lambda x: colorize.make(x).yellow # noqa | |
70 | blue = lambda x: colorize.make(x).blue # noqa | |
71 | green = lambda x: colorize.make(x).green # noqa | |
72 | red = lambda x: colorize.make(x).red # noqa | |
73 | bold = lambda x: colorize.make(x).bold # noqa | |
74 | red_arrow = red('--> ') | |
75 | blue_arrow = blue('--> ') | |
76 | green_arrow = green('--> ') | |
77 | yellow_arrow = yellow('--> ') | |
78 | ||
79 | ||
80 | class _Write(object): | |
81 | ||
82 | def __init__(self, _writer=None, prefix='', suffix='', flush=False): | |
83 | self._writer = _writer or sys.stdout | |
84 | self.suffix = suffix | |
85 | self.prefix = prefix | |
86 | self.flush = flush | |
87 | ||
88 | def bold(self, string): | |
89 | self.write(bold(string)) | |
90 | ||
91 | def raw(self, string): | |
92 | if not string.endswith('\n'): | |
93 | string = '%s\n' % string | |
94 | self.write(string) | |
95 | ||
96 | def write(self, line): | |
97 | self._writer.write(self.prefix + line + self.suffix) | |
98 | if self.flush: | |
99 | self._writer.flush() | |
100 | ||
101 | ||
102 | def stdout(msg): | |
103 | return _Write(prefix=blue(' stdout: ')).raw(msg) | |
104 | ||
105 | ||
106 | def stderr(msg): | |
107 | return _Write(prefix=yellow(' stderr: ')).raw(msg) | |
108 | ||
109 | ||
110 | def write(msg): | |
111 | return _Write().raw(msg) | |
112 | ||
113 | ||
114 | def error(msg): | |
115 | return _Write(prefix=red_arrow).raw(msg) | |
116 | ||
117 | ||
b32b8144 FG |
118 | def info(msg): |
119 | return _Write(prefix=blue_arrow).raw(msg) | |
120 | ||
121 | ||
122 | def debug(msg): | |
123 | return _Write(prefix=blue_arrow).raw(msg) | |
124 | ||
125 | ||
d2e6a577 FG |
126 | def warning(msg): |
127 | return _Write(prefix=yellow_arrow).raw(msg) | |
128 | ||
129 | ||
130 | def success(msg): | |
131 | return _Write(prefix=green_arrow).raw(msg) | |
132 | ||
133 | ||
b32b8144 FG |
134 | class MultiLogger(object): |
135 | """ | |
136 | Proxy class to be able to report on both logger instances and terminal | |
137 | messages avoiding the issue of having to call them both separately | |
138 | ||
139 | Initialize it in the same way a logger object:: | |
140 | ||
141 | logger = terminal.MultiLogger(__name__) | |
142 | """ | |
143 | ||
144 | def __init__(self, name): | |
145 | self.logger = logging.getLogger(name) | |
146 | ||
147 | def _make_record(self, msg, *args): | |
148 | if len(str(args)): | |
149 | try: | |
150 | return msg % args | |
151 | except TypeError: | |
152 | self.logger.exception('unable to produce log record: %s' % msg) | |
153 | return msg | |
154 | ||
155 | def warning(self, msg, *args): | |
156 | record = self._make_record(msg, *args) | |
157 | warning(record) | |
158 | self.logger.warning(record) | |
159 | ||
160 | def debug(self, msg, *args): | |
161 | record = self._make_record(msg, *args) | |
162 | debug(record) | |
163 | self.logger.debug(record) | |
164 | ||
165 | def info(self, msg, *args): | |
166 | record = self._make_record(msg, *args) | |
167 | info(record) | |
168 | self.logger.info(record) | |
169 | ||
170 | def error(self, msg, *args): | |
171 | record = self._make_record(msg, *args) | |
172 | error(record) | |
173 | self.logger.error(record) | |
174 | ||
175 | ||
d2e6a577 FG |
176 | def dispatch(mapper, argv=None): |
177 | argv = argv or sys.argv | |
178 | for count, arg in enumerate(argv, 1): | |
179 | if arg in mapper.keys(): | |
180 | instance = mapper.get(arg)(argv[count:]) | |
181 | if hasattr(instance, 'main'): | |
182 | instance.main() | |
183 | raise SystemExit(0) | |
184 | ||
185 | ||
186 | def subhelp(mapper): | |
187 | """ | |
188 | Look at every value of every key in the mapper and will output any | |
189 | ``class.help`` possible to return it as a string that will be sent to | |
190 | stdout. | |
191 | """ | |
192 | help_text_lines = [] | |
193 | for key, value in mapper.items(): | |
194 | try: | |
195 | help_text = value.help | |
196 | except AttributeError: | |
197 | continue | |
198 | help_text_lines.append("%-24s %s" % (key, help_text)) | |
199 | ||
200 | if help_text_lines: | |
201 | return "Available subcommands:\n\n%s" % '\n'.join(help_text_lines) | |
202 | return '' |