Package entropy :: Module output

Source Code for Module entropy.output

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <[email protected]> 
   5      @contact: [email protected] 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Framework Output module}. 
  10   
  11      This module contains Entropy (user) Output classes and routines. 
  12   
  13  """ 
  14  import os 
  15  import sys 
  16  import errno 
  17  import curses 
  18  import subprocess 
  19  import threading 
  20   
  21  from entropy.const import const_convert_to_rawstring, \ 
  22      const_isstring, const_convert_to_unicode, const_isunicode, \ 
  23      const_is_python3 
  24  from entropy.i18n import _ 
  25   
  26  stuff = {} 
  27  stuff['cols'] = 30 
  28  try: 
  29      curses.setupterm() 
  30      stuff['cols'] = curses.tigetnum('cols') 
  31  except: 
  32      pass 
  33  stuff['cleanline'] = "" 
34 -def setcols():
35 stuff['cleanline'] = "" 36 count = stuff['cols'] 37 while count: 38 stuff['cleanline'] += ' ' 39 count -= 1
40 setcols() 41 stuff['cursor'] = False 42 stuff['ESC'] = chr(27) 43 44 havecolor=1 45 global dotitles 46 dotitles=1 47 48 esc_seq = "\x1b[" 49 50 g_attr = {} 51 g_attr["normal"] = 0 52 53 g_attr["bold"] = 1 54 g_attr["faint"] = 2 55 g_attr["standout"] = 3 56 g_attr["underline"] = 4 57 g_attr["blink"] = 5 58 g_attr["overline"] = 6 # Why is overline actually useful? 59 g_attr["reverse"] = 7 60 g_attr["invisible"] = 8 61 62 g_attr["no-attr"] = 22 63 g_attr["no-standout"] = 23 64 g_attr["no-underline"] = 24 65 g_attr["no-blink"] = 25 66 g_attr["no-overline"] = 26 67 g_attr["no-reverse"] = 27 68 # 28 isn't defined? 69 # 29 isn't defined? 70 g_attr["black"] = 30 71 g_attr["red"] = 31 72 g_attr["green"] = 32 73 g_attr["yellow"] = 33 74 g_attr["blue"] = 34 75 g_attr["magenta"] = 35 76 g_attr["cyan"] = 36 77 g_attr["white"] = 37 78 # 38 isn't defined? 79 g_attr["default"] = 39 80 g_attr["bg_black"] = 40 81 g_attr["bg_red"] = 41 82 g_attr["bg_green"] = 42 83 g_attr["bg_yellow"] = 43 84 g_attr["bg_blue"] = 44 85 g_attr["bg_magenta"] = 45 86 g_attr["bg_cyan"] = 46 87 g_attr["bg_white"] = 47 88 g_attr["bg_default"] = 49
89 90 # make_seq("blue", "black", "normal") 91 -def color(fg, bg="default", attr=["normal"]):
92 mystr = esc_seq[:] + "%02d" % g_attr[fg] 93 for x in [bg]+attr: 94 mystr += ";%02d" % g_attr[x] 95 return mystr+"m"
96 97 codes = {} 98 codes["reset"] = esc_seq + "39;49;00m" 99 100 codes["bold"] = esc_seq + "01m" 101 codes["faint"] = esc_seq + "02m" 102 codes["standout"] = esc_seq + "03m" 103 codes["underline"] = esc_seq + "04m" 104 codes["blink"] = esc_seq + "05m" 105 codes["overline"] = esc_seq + "06m" # Who made this up? Seriously. 106 107 ansi_color_codes = [] 108 for x in range(30, 38): 109 ansi_color_codes.append("%im" % x) 110 ansi_color_codes.append("%i;01m" % x) 111 112 rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00', 113 '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA', 114 '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF'] 115 116 for x in range(len(rgb_ansi_colors)): 117 codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x] 118 119 codes["black"] = codes["0x000000"] 120 codes["darkgray"] = codes["0x555555"] 121 122 codes["red"] = codes["0xFF5555"] 123 codes["darkred"] = codes["0xAA0000"] 124 125 codes["green"] = codes["0x55FF55"] 126 codes["darkgreen"] = codes["0x00AA00"] 127 128 codes["yellow"] = codes["0xFFFF55"] 129 codes["brown"] = codes["0xAA5500"] 130 131 codes["blue"] = codes["0x5555FF"] 132 codes["darkblue"] = codes["0x0000AA"] 133 134 codes["fuchsia"] = codes["0xFF55FF"] 135 codes["purple"] = codes["0xAA00AA"] 136 137 codes["turquoise"] = codes["0x55FFFF"] 138 codes["teal"] = codes["0x00AAAA"] 139 140 codes["white"] = codes["0xFFFFFF"] 141 codes["lightgray"] = codes["0xAAAAAA"] 142 143 codes["darkteal"] = codes["turquoise"] 144 codes["darkyellow"] = codes["brown"] 145 codes["fuscia"] = codes["fuchsia"] 146 codes["white"] = codes["bold"] 147 148 149 # mute flag, will mute any stdout/stderr output. 150 _MUTE = os.getenv("ETP_MUTE") is not None 151 # interactive flag, this will go away at some point in future 152 _INTERACTIVE = os.getenv("ETP_NONINTERACTIVE") is None
153 154 -def is_mute():
155 """ 156 Return whether writing to stderr/stdout is allowed. 157 158 @return: mute status 159 @rtype: bool 160 """ 161 return _MUTE
162
163 -def set_mute(status):
164 """ 165 Set mute status. 166 167 @param status: new mute status 168 @type status: bool 169 """ 170 global _MUTE 171 _MUTE = bool(status)
172
173 -def is_interactive():
174 """ 175 Return whether interactive mode is enabled. 176 177 @return: True, if interactive is enabled 178 @rtype: bool 179 """ 180 return _INTERACTIVE
181
182 -def is_stdout_a_tty():
183 """ 184 Return whether current stdout is a TTY. 185 186 @return: tty? => True 187 @rtype: bool 188 """ 189 # Paster LazyWriter (Pyramid/Pylons) 190 if not hasattr(sys.stdout, "fileno"): 191 return False 192 fn = sys.stdout.fileno() 193 return os.isatty(fn)
194
195 -def xterm_title(mystr, raw = False):
196 """ 197 Set new xterm title. 198 199 @param mystr: new xterm title 200 @type mystr: string 201 @keyword raw: write title in raw mode 202 @type raw: bool 203 """ 204 if dotitles and "TERM" in os.environ and sys.stderr.isatty(): 205 myt = os.environ["TERM"] 206 legal_terms = ("xterm", "Eterm", "aterm", "rxvt", "screen", 207 "kterm", "rxvt-unicode", "gnome") 208 if myt in legal_terms: 209 if not raw: 210 mystr = "\x1b]0;%s\x07" % mystr 211 try: 212 sys.stderr.write(mystr) 213 except UnicodeEncodeError: 214 sys.stderr.write(mystr.encode('utf-8')) 215 sys.stderr.flush()
216 217 default_xterm_title = None
218 219 -def xterm_title_reset():
220 """ 221 Reset xterm title to default. 222 """ 223 global default_xterm_title 224 if default_xterm_title is None: 225 prompt_command = os.getenv('PROMPT_COMMAND') 226 if not prompt_command: 227 default_xterm_title = "" 228 elif prompt_command is not None: 229 from entropy.tools import getstatusoutput 230 default_xterm_title = getstatusoutput(prompt_command)[1] 231 else: 232 pwd = os.getenv('PWD', '') 233 home = os.getenv('HOME', '') 234 if home != '' and pwd.startswith(home): 235 pwd = '~' + pwd[len(home):] 236 default_xterm_title = '\x1b]0;%[email protected]%s:%s\x07' % ( 237 os.getenv('LOGNAME', ''), 238 os.getenv('HOSTNAME', '').split('.', 1)[0], 239 pwd) 240 xterm_title(default_xterm_title, raw = True)
241
242 -def notitles():
243 """ 244 Turn off title setting. In this way, xterm title won't be touched. 245 """ 246 global dotitles 247 dotitles=0
248
249 -def nocolor():
250 """ 251 Turn off colorization process-wide. 252 """ 253 os.environ['ETP_NO_COLOR'] = "1" 254 global havecolor 255 havecolor=0
256
257 -def getcolor():
258 """ 259 Return color status 260 """ 261 return havecolor
262 263 nc = os.getenv("ETP_NO_COLOR") 264 if nc: 265 nocolor()
266 267 -def _reset_color():
268 """ 269 Reset terminal color currently set. 270 """ 271 return codes["reset"]
272
273 -def colorize(color_key, text):
274 """ 275 Colorize text with given color key using bash/terminal codes. 276 277 @param color_key: color identifier available in entropy.output.codes 278 @type color_key: string 279 @return: coloured text 280 @rtype: string 281 """ 282 if is_mute(): 283 return text 284 global havecolor 285 if havecolor: 286 return codes[color_key] + text + codes["reset"] 287 return text
288
289 -def decolorize(text):
290 my_esc_seq = "\x1b" 291 new_text = '' 292 append = True 293 for char in text: 294 if char == my_esc_seq: 295 append = False 296 continue 297 elif char == "m" and not append: 298 append = True 299 continue 300 if append: 301 new_text += char 302 return new_text
303
304 -def bold(text):
305 """ 306 Make text bold using bash/terminal codes. 307 308 @param text: text to colorize 309 @type text: string 310 @return: colorized text 311 @rtype: string 312 """ 313 return colorize("bold", text)
314
315 -def white(text):
316 """ 317 Make text white using bash/terminal codes. 318 319 @param text: text to colorize 320 @type text: string 321 @return: colorized text 322 @rtype: string 323 """ 324 return colorize("white", text)
325
326 -def teal(text):
327 """ 328 Make text teal using bash/terminal codes. 329 330 @param text: text to colorize 331 @type text: string 332 @return: colorized text 333 @rtype: string 334 """ 335 return colorize("teal", text)
336
337 -def turquoise(text):
338 """ 339 Make text turquoise using bash/terminal codes. 340 341 @param text: text to colorize 342 @type text: string 343 @return: colorized text 344 @rtype: string 345 """ 346 return colorize("turquoise", text)
347
348 -def darkteal(text):
349 """ 350 Make text darkteal using bash/terminal codes. 351 352 @param text: text to colorize 353 @type text: string 354 @return: colorized text 355 @rtype: string 356 """ 357 return colorize("darkteal", text)
358
359 -def purple(text):
360 """ 361 Make text purple using bash/terminal codes. 362 363 @param text: text to colorize 364 @type text: string 365 @return: colorized text 366 @rtype: string 367 """ 368 return colorize("purple", text)
369
370 -def blue(text):
371 """ 372 Make text blue using bash/terminal codes. 373 374 @param text: text to colorize 375 @type text: string 376 @return: colorized text 377 @rtype: string 378 """ 379 return colorize("blue", text)
380
381 -def darkblue(text):
382 """ 383 Make text darkblue using bash/terminal codes. 384 385 @param text: text to colorize 386 @type text: string 387 @return: colorized text 388 @rtype: string 389 """ 390 return colorize("darkblue", text)
391
392 -def green(text):
393 """ 394 Make text green using bash/terminal codes. 395 396 @param text: text to colorize 397 @type text: string 398 @return: colorized text 399 @rtype: string 400 """ 401 return colorize("green", text)
402
403 -def darkgreen(text):
404 """ 405 Make text darkgreen using bash/terminal codes. 406 407 @param text: text to colorize 408 @type text: string 409 @return: colorized text 410 @rtype: string 411 """ 412 return colorize("darkgreen", text)
413
414 -def yellow(text):
415 """ 416 Make text yellow using bash/terminal codes. 417 418 @param text: text to colorize 419 @type text: string 420 @return: colorized text 421 @rtype: string 422 """ 423 return colorize("yellow", text)
424
425 -def brown(text):
426 """ 427 Make text brown using bash/terminal codes. 428 429 @param text: text to colorize 430 @type text: string 431 @return: colorized text 432 @rtype: string 433 """ 434 return colorize("brown", text)
435
436 -def darkyellow(text):
437 """ 438 Make text darkyellow using bash/terminal codes. 439 440 @param text: text to colorize 441 @type text: string 442 @return: colorized text 443 @rtype: string 444 """ 445 return colorize("darkyellow", text)
446
447 -def red(text):
448 """ 449 Make text red using bash/terminal codes. 450 451 @param text: text to colorize 452 @type text: string 453 @return: colorized text 454 @rtype: string 455 """ 456 return colorize("red", text)
457
458 -def darkred(text):
459 """ 460 Make text darkred using bash/terminal codes. 461 462 @param text: text to colorize 463 @type text: string 464 @return: colorized text 465 @rtype: string 466 """ 467 return colorize("darkred", text)
468
469 -def reset_cursor():
470 """ 471 Print to stdout the terminal code to push back cursor at the beginning 472 of the line. 473 """ 474 if havecolor: 475 sys.stdout.write(stuff['ESC'] + '[2K') 476 _flush_stdouterr()
477
478 -def _flush_stdouterr():
479 for obj in (sys.stdout, sys.stderr,): 480 try: 481 obj.flush() 482 except IOError: 483 continue
484
485 -def _std_write(msg, stderr = False):
486 if not const_isstring(msg): 487 msg = repr(msg) 488 obj = sys.stdout 489 if stderr: 490 obj = sys.stderr 491 492 try: 493 obj.write(msg) 494 except UnicodeEncodeError: 495 msg = msg.encode('utf-8') 496 if const_is_python3(): 497 obj.buffer.write(msg) 498 else: 499 obj.write(msg)
500 501 MESSAGE_HEADER = const_convert_to_unicode("\u2560 ") # ╠ 502 ERROR_MESSAGE_HEADER = const_convert_to_unicode("\u2622 ") # ☢ 503 WARNING_MESSAGE_HEADER = const_convert_to_unicode("\u261B ") # ☛
504 505 -def _print_prio(msg, color_func, back = False, flush = True, end = '\n', 506 stderr = False, msg_header = None):
507 if is_mute(): 508 return 509 if not back: 510 setcols() 511 reset_cursor() 512 is_tty = is_stdout_a_tty() 513 if is_tty: 514 writechar("\r", stderr = stderr) 515 516 if msg_header is None: 517 msg_header = MESSAGE_HEADER 518 header = color_func(msg_header) 519 520 _std_write(header, stderr = stderr) 521 _std_write(msg, stderr = stderr) 522 if not back: 523 _std_write(end, stderr = stderr) 524 525 if back and (not is_tty): 526 # in this way files are properly written 527 writechar("\n", stderr = stderr) 528 if flush: 529 _flush_stdouterr()
530 548 565 583 604
605 -def writechar(chars, stderr = False):
606 """ 607 Write characters to stdout (will be moved from here). 608 609 @param chars: chars to write 610 @type chars: string 611 """ 612 if is_mute(): 613 return 614 obj = sys.stdout 615 if stderr: 616 obj = sys.stderr 617 try: 618 obj.write(chars) 619 obj.flush() 620 except IOError as e: 621 if e.errno == errno.EPIPE: 622 return 623 raise
624
625 -def readtext(request, password = False):
626 """ 627 Read text from stdin and return it (will be moved from here). 628 629 @param request: textual request to print 630 @type request: string 631 @keyword password: if you are requesting a password, set this to True 632 @type password: bool 633 @return: text read back from stdin 634 @rtype: string 635 @raise EOFError: if CTRL+D is pressed 636 """ 637 xterm_title(_("Entropy needs your attention")) 638 if password: 639 from getpass import getpass 640 try: 641 text = getpass(request+" ") 642 except UnicodeEncodeError: 643 text = getpass(request.encode('utf-8')+" ") 644 else: 645 try: 646 sys.stdout.write(request) 647 except UnicodeEncodeError: 648 sys.stdout.write(request.encode('utf-8')) 649 _flush_stdouterr() 650 text = _my_raw_input() 651 return text
652
653 -def _my_raw_input(txt = ''):
654 try: 655 import readline 656 except ImportError: 657 # not available? ignore 658 pass 659 660 if not txt: 661 txt = "" 662 if const_is_python3(): 663 try: 664 response = input(darkgreen(txt)) 665 except UnicodeEncodeError: 666 response = input(darkgreen(txt.encode('utf-8'))) 667 else: 668 try: 669 response = raw_input(darkgreen(txt)) 670 except UnicodeEncodeError: 671 response = raw_input(darkgreen(txt.encode('utf-8'))) 672 _flush_stdouterr() 673 674 # try to convert to unicode, because responses are stored that 675 # way, fix bug #2006. 676 if not const_isunicode(response): 677 try: 678 response = const_convert_to_unicode(response, enctype = "utf-8") 679 except (UnicodeDecodeError, UnicodeEncodeError): 680 # be fault tolerant, we just tried 681 pass 682 return response
683
684 -class TextInterface(object):
685 686 """ 687 TextInterface is a base class for handling the communication between 688 user and Entropy-based applications. 689 690 This class works for text-based applications, it must be inherited 691 from subclasses and its methods reimplemented to make Entropy working 692 on situations where a terminal is not used as UI (Graphical applications, 693 web-based interfaces, remote interfaces, etc). 694 695 Every part of Entropy is using the methods in this class to communicate 696 with the user, channel is bi-directional. 697 """ 698 699 OUTPUT_LOCK = threading.RLock() 700 701 @classmethod
702 - def output(cls, text, header = "", footer = "", back = False, 703 importance = 0, level = "info", count = None, percent = False):
704 705 """ 706 Text output print function. By default text is written to stdout. 707 708 @param text: text to write to stdout 709 @type text: string 710 @keyword header: text header (decoration?) 711 @type header: string 712 @keyword footer: text footer (decoration?) 713 @type footer: string 714 @keyword back: push back cursor to the beginning of the line 715 @type back: bool 716 @keyword importance: message importance (default valid values: 717 0, 1, 2, 3 718 @type importance: int 719 @keyword level: message type (default valid values: "info", "warning", 720 "error", "generic") 721 @type level: string 722 @keyword count: tuple of lengh 2, containing count information to make 723 function print something like "(10/100) doing stuff". In this case 724 tuple would be: (10, 100,) 725 @type count: tuple 726 @keyword percent: determine whether "count" argument should be printed 727 as percentual value (for values like (10, 100,), "(10%) doing stuff" 728 will be printed. 729 @keyword percent: bool 730 @return: None 731 @rtype: None 732 """ 733 734 if is_mute(): 735 return 736 737 _flush_stdouterr() 738 739 myfunc = print_info 740 if level == "warning": 741 myfunc = print_warning 742 elif level == "error": 743 myfunc = print_error 744 elif level == "generic": 745 myfunc = print_generic 746 747 count_str = "" 748 if count: 749 if len(count) > 1: 750 if percent: 751 percent_str = str(round((float(count[0])/count[1])*100, 1)) 752 count_str = " ("+percent_str+"%) " 753 else: 754 count_str = " (%s/%s) " % (red(str(count[0])), 755 blue(str(count[1])),) 756 757 with TextInterface.OUTPUT_LOCK: 758 myfunc(header+count_str+text+footer, back = back, flush = False) 759 _flush_stdouterr()
760 761 @classmethod
762 - def ask_question(cls, question, importance = 0, responses = None):
763 764 """ 765 Questions asking function. It asks the user to answer the question given 766 by choosing between a preset list of answers given by the "reposonses" 767 argument. 768 769 @param question: question text 770 @type question: string 771 @keyword importance: question importance (no default valid values) 772 @type importance: int 773 @keyword responses: list of valid answers which user has to choose from 774 @type responses: tuple or list 775 @return: None 776 @rtype: None 777 """ 778 779 if responses is None: 780 responses = (_("Yes"), _("No"),) 781 782 colours = [green, red, blue, darkgreen, darkred, darkblue, 783 brown, purple] 784 colours_len = len(colours) 785 786 try: 787 sys.stdout.write(question + " ") 788 except UnicodeEncodeError: 789 sys.stdout.write(question.encode('utf-8') + " ") 790 _flush_stdouterr() 791 792 try: 793 while True: 794 795 xterm_title(_("Entropy got a question for you")) 796 _flush_stdouterr() 797 answer_items = [colours[x % colours_len](responses[x]) \ 798 for x in range(len(responses))] 799 response = _my_raw_input("["+"/".join(answer_items)+"] ") 800 _flush_stdouterr() 801 802 for key in responses: 803 if response.upper() == key[:len(response)].upper(): 804 xterm_title_reset() 805 return key 806 _flush_stdouterr() 807 808 except (EOFError, KeyboardInterrupt): 809 msg = "%s.\n" % (_("Interrupted"),) 810 try: 811 sys.stdout.write(msg) 812 except UnicodeEncodeError: 813 sys.stdout.write(msg.encode("utf-8")) 814 xterm_title_reset() 815 raise KeyboardInterrupt() 816 817 xterm_title_reset() 818 _flush_stdouterr()
819 820 @classmethod
821 - def input_box(cls, title, input_parameters, cancel_button = True):
822 """ 823 Generic input box (form) creator and data collector. 824 825 @param title: input box title 826 @type title: string 827 @param input_parameters: list of properly formatted tuple items. 828 @type input_parameters: list 829 @keyword cancel_button: make possible to "cancel" the input request. 830 @type cancel_button: bool 831 @return: dict containing input box answers 832 @rtype: dict 833 834 input_parameters supported items: 835 836 [input id], [input text title], [input verification callback], [ 837 no text echo?] 838 ('identifier 1', 'input text 1', input_verification_callback, False) 839 840 ('item_3', ('checkbox', 'Checkbox option (boolean request) - please choose',), 841 input_verification_callback, True) 842 843 ('item_4', ('combo', ('Select your favorite option', ['option 1', 'option 2', 'option 3']),), 844 input_verification_callback, True) 845 846 ('item_4',('list',('Setup your list',['default list item 1', 'default list item 2']),), 847 input_verification_callback, True) 848 849 """ 850 results = {} 851 if title: 852 try: 853 sys.stdout.write(title + "\n") 854 except UnicodeEncodeError: 855 sys.stdout.write(title.encode('utf-8') + "\n") 856 _flush_stdouterr() 857 858 def option_chooser(option_data): 859 mydict = {} 860 counter = 1 861 option_text, option_list = option_data 862 cls.output(option_text) 863 for item in option_list: 864 mydict[counter] = item 865 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 866 cls.output(txt) 867 counter += 1 868 while True: 869 try: 870 if const_is_python3(): 871 myresult = const_convert_to_unicode( 872 readtext("%s: " % (_('Selected number'),)), 873 enctype = "utf-8") 874 else: 875 myresult = readtext( 876 "%s: " % (_('Selected number'),)).decode('utf-8') 877 except UnicodeDecodeError: 878 continue 879 except UnicodeEncodeError: 880 continue 881 try: 882 myresult = int(myresult) 883 except ValueError: 884 continue 885 selected = mydict.get(myresult) 886 if selected != None: 887 return myresult, selected
888 889 def list_editor(option_data, can_cancel, callback): 890 891 def selaction(): 892 cls.output('') 893 cls.output(darkred(_("Please select an option"))) 894 if can_cancel: 895 cls.output(" ("+blue("-1")+") "+darkred(_("Discard all"))) 896 cls.output(" ("+blue("0")+") "+darkgreen(_("Confirm"))) 897 cls.output(" ("+blue("1")+") "+brown(_("Add item"))) 898 cls.output(" ("+blue("2")+") "+brown(_("Edit item"))) 899 cls.output(" ("+blue("3")+") "+darkblue(_("Remove item"))) 900 cls.output(" ("+blue("4")+") "+darkgreen(_("Show current list"))) 901 # wait user interaction 902 cls.output('') 903 try: 904 action = readtext(darkgreen(_("Your choice (type a number and press enter):"))+" ") 905 except UnicodeDecodeError: 906 return '' 907 return action
908 909 mydict = {} 910 counter = 1 911 valid_actions = [0, 1, 2, 3, 4] 912 if can_cancel: 913 valid_actions.insert(0, -1) 914 option_text, option_list = option_data 915 txt = "%s:" % (blue(option_text),) 916 cls.output(txt) 917 918 for item in option_list: 919 mydict[counter] = item 920 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 921 cls.output(txt) 922 counter += 1 923 924 def show_current_list(): 925 for key in sorted(mydict): 926 txt = "[%s] %s" % (darkgreen(str(key)), blue(mydict[key]),) 927 cls.output(txt) 928 929 while True: 930 try: 931 sel_action = selaction() 932 if not sel_action: 933 show_current_list() 934 action = int(sel_action) 935 except (ValueError, TypeError,): 936 cls.output(_("You don't have typed a number."), level = "warning") 937 continue 938 if action not in valid_actions: 939 cls.output(_("Invalid action."), level = "warning") 940 continue 941 if action == -1: 942 raise KeyboardInterrupt() 943 elif action == 0: 944 break 945 elif action == 1: # add item 946 while True: 947 try: 948 try: 949 s_el = readtext(darkred(_("String to add (-1 to go back):"))+" ") 950 except UnicodeDecodeError: 951 raise ValueError() 952 if s_el == "-1": 953 break 954 if not callback(s_el): 955 raise ValueError() 956 mydict[counter] = s_el 957 counter += 1 958 except (ValueError,): 959 cls.output(_("Invalid string."), level = "warning") 960 continue 961 break 962 show_current_list() 963 continue 964 elif action == 2: # edit item 965 while True: 966 try: 967 edit_msg = _("Element number to edit (-1 to go back):") 968 try: 969 s_el = int(readtext(darkred(edit_msg)+" ")) 970 except UnicodeDecodeError: 971 raise ValueError() 972 if s_el == -1: 973 break 974 if s_el not in mydict: 975 raise ValueError() 976 try: 977 new_s_val = readtext("[%s: %s] %s " % ( 978 _("old"), mydict[s_el], _("new value:"),) 979 ) 980 except UnicodeDecodeError: 981 new_s_val = '' 982 if not callback(new_s_val): 983 raise ValueError() 984 mydict[s_el] = new_s_val[:] 985 except (ValueError, TypeError,): 986 cls.output(_("Invalid element."), level = "warning") 987 continue 988 break 989 show_current_list() 990 continue 991 elif action == 3: # remove item 992 while True: 993 try: 994 try: 995 s_el = int(readtext(darkred(_("Element number to remove (-1 to go back):"))+" ")) 996 except UnicodeDecodeError: 997 raise ValueError() 998 if s_el == -1: 999 break 1000 if s_el not in mydict: 1001 raise ValueError() 1002 del mydict[s_el] 1003 except (ValueError, TypeError,): 1004 cls.output(_("Invalid element."), level = "warning") 1005 continue 1006 break 1007 show_current_list() 1008 continue 1009 elif action == 4: # show current list 1010 show_current_list() 1011 continue 1012 break 1013 1014 mylist = [mydict[x] for x in sorted(mydict)] 1015 return mylist 1016 1017 for identifier, input_text, callback, password in input_parameters: 1018 while True: 1019 use_cb = True 1020 try: 1021 if isinstance(input_text, tuple): 1022 myresult = False 1023 input_type, data = input_text 1024 if input_type == "checkbox": 1025 answer = cls.ask_question(data) 1026 if answer == _("Yes"): 1027 myresult = True 1028 elif input_type == "combo": 1029 myresult = option_chooser(data) 1030 elif input_type == "list": 1031 use_cb = False 1032 myresult = list_editor(data, cancel_button, callback) 1033 else: 1034 while True: 1035 try: 1036 myresult = readtext(input_text+": ", password = password).decode('utf-8') 1037 except UnicodeDecodeError: 1038 continue 1039 break 1040 except (KeyboardInterrupt, EOFError,): 1041 if not cancel_button: # use with care 1042 continue 1043 return None 1044 valid = True 1045 if use_cb: 1046 valid = callback(myresult) 1047 if valid: 1048 results[identifier] = myresult 1049 break 1050 return results 1051 1052 @classmethod
1053 - def edit_file(cls, file_path):
1054 """ 1055 Open a file editor on given file path (file_path). 1056 1057 @param file_path: path to a writeable file 1058 @type file_path: string 1059 @return: True for successful edit, False otherwise 1060 @rtype: bool 1061 """ 1062 editor = os.getenv("EDITOR", "/bin/nano") 1063 return subprocess.call((editor, file_path)) == 0
1064 1065 @classmethod
1066 - def set_title(cls, title):
1067 """ 1068 Set application title. 1069 1070 @param title: new application title 1071 @type title: string 1072 """ 1073 xterm_title(title)
1074