Fix day filter
[cds-indico.git] / indico / util / console.py
blob615a1125201a4c5d1063e63f584409f927d5e2f0
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from __future__ import division, absolute_import, print_function
19 import fcntl
20 import re
21 import struct
22 import sys
23 import termios
24 import time
25 from operator import itemgetter
26 from getpass import getpass
28 from colorclass import Color
30 from indico.util.string import is_valid_mail, to_unicode
33 def strip_ansi(s, _re=re.compile(r'\x1b\[[;\d]*[A-Za-z]')):
34 return _re.sub('', s)
37 def yesno(message):
38 """
39 A simple yes/no question (returns True/False)
40 """
41 inp = raw_input("%s [y/N] " % message)
42 if inp == 'y' or inp == 'Y':
43 return True
44 else:
45 return False
48 def prompt_email(prompt="Enter email: "):
49 while True:
50 try:
51 email = unicode(raw_input(prompt.encode(sys.stderr.encoding)), sys.stdin.encoding).strip()
52 except (EOFError, KeyboardInterrupt): # ^D or ^C
53 print()
54 return None
55 if is_valid_mail(email):
56 return email
57 else:
58 warning(u"Email format is invalid")
61 def prompt_pass(prompt=u"Enter password: ", confirm_prompt=u"Confirm password: ", min_length=8, confirm=True):
62 while True:
63 try:
64 password = unicode(getpass(prompt.encode(sys.stderr.encoding)), sys.stdin.encoding).strip()
65 except (EOFError, KeyboardInterrupt): # ^D or ^C
66 print()
67 return None
68 # Empty, just prompt again
69 if not password:
70 continue
71 # Too short, tell the user about the fact
72 if min_length and len(password) < min_length:
73 warning(u"Password is too short (must be at least {} chars)".format(min_length))
74 continue
75 # Confirm password if requested
76 if not confirm:
77 return password
78 while True:
79 confirmation = prompt_pass(confirm_prompt, min_length=0, confirm=False)
80 if not confirmation:
81 return None
82 elif confirmation == password:
83 return password
84 else:
85 warning(u"Passwords don't match")
88 def terminal_size():
89 h, w, hp, wp = struct.unpack('HHHH', fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))
90 return w, h
93 def clear_line():
94 """Clears the current line in the terminal"""
95 print('\r', ' ' * terminal_size()[0], '\r', end='', sep='')
98 def verbose_iterator(iterable, total, get_id, get_title, print_every=10):
99 """Iterates large iterables verbosely
101 :param iterable: An iterable
102 :param total: The number of items in `iterable`
103 :param get_id: callable to retrieve the ID of an item
104 :param get_title: callable to retrieve the title of an item
106 term_width = terminal_size()[0]
107 start_time = time.time()
108 fmt = cformat(
109 '[%{cyan!}{:6}%{reset}/%{cyan}{}%{reset} %{yellow!}{:.3f}%{reset}% %{green!}{}%{reset}] {:>8} %{grey!}{}'
112 for i, item in enumerate(iterable, 1):
113 if i % print_every == 0 or i == total:
114 remaining_seconds = int((time.time() - start_time) / i * (total - i))
115 remaining = '{:02}:{:02}'.format(remaining_seconds // 60, remaining_seconds % 60)
116 title = to_unicode(get_title(item).replace('\n', ' '))
117 text = fmt.format(i, total, (i / total * 100.0), remaining, get_id(item), title)
118 print('\r', ' ' * term_width, end='', sep='')
119 # terminal width + ansi control code length - trailing reset code (4)
120 print('\r', text[:term_width + len(text.value_colors) - len(text.value_no_colors) - 4], cformat('%{reset}'),
121 end='', sep='')
122 sys.stdout.flush()
124 yield item
126 print()
129 def conferenceHolderIterator(ch, verbose=True, deepness='subcontrib'):
131 Goes over all conferences, printing a status message (ideal for scripts)
134 def _eventIterator(conference, tabs):
135 for contrib in conference.getContributionList():
136 yield ('contrib', contrib)
138 if deepness == 'subcontrib':
139 for scontrib in contrib.getSubContributionList():
140 yield ('subcontrib', scontrib)
142 idx = ch._getIdx()
143 iterator = idx.iteritems()
144 if verbose:
145 iterator = verbose_iterator(iterator, len(idx.keys()), itemgetter(0), lambda x: x[1].getTitle())
147 for id_, conf in iterator:
148 yield 'event', conf
149 if deepness in {'contrib', 'subcontrib'}:
150 for contrib in _eventIterator(conf, 0):
151 yield contrib
154 # Coloring
156 try:
157 from termcolor import colored
158 except ImportError:
159 def colored(text, *__, **___):
161 just a dummy function that returns the same string
162 (in case termcolor is not available)
164 return text
167 def _cformat_sub(m):
168 bg = u'on_{}'.format(m.group('bg')) if m.group('bg') else None
169 attrs = ['bold'] if m.group('fg_bold') else None
170 return colored(u'', m.group('fg'), bg, attrs=attrs)[:-4]
173 def cformat(string):
174 """Replaces %{color} and %{color,bgcolor} with ansi colors.
176 Bold foreground can be achieved by suffixing the color with a '!'
178 reset = colored(u'')
179 string = string.replace(u'%{reset}', reset)
180 string = re.sub(ur'%\{(?P<fg>[a-z]+)(?P<fg_bold>!?)(?:,(?P<bg>[a-z]+))?}', _cformat_sub, string)
181 if not string.endswith(reset):
182 string += reset
183 return Color(string)
186 # Error/warning/info message util methods
188 def error(message):
190 Print a red error message
192 print(colored(message, 'red'))
195 def warning(message):
197 Print a yellow warning message
199 print(colored(message, 'yellow'))
202 def info(message):
204 Print a blue information message
206 print(colored(message, 'cyan', attrs=['bold']))
209 def success(message):
211 Print a green success message
213 print(colored(message, 'green'))