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 if const_is_python3() and not const_isunicode(msg): 493 obj.flush() 494 obj.buffer.write(msg) 495 obj.flush() 496 return 497 498 try: 499 obj.write(msg) 500 except UnicodeEncodeError: 501 msg = msg.encode('utf-8') 502 if const_is_python3(): 503 obj.buffer.write(msg) 504 else: 505 obj.write(msg)
506 507 MESSAGE_HEADER = const_convert_to_unicode("\u2560 ") # ╠ 508 ERROR_MESSAGE_HEADER = const_convert_to_unicode("\u2622 ") # ☢ 509 WARNING_MESSAGE_HEADER = const_convert_to_unicode("\u261B ") # ☛
510 511 -def _print_prio(msg, color_func, back = False, flush = True, end = '\n', 512 stderr = False, msg_header = None):
513 if is_mute(): 514 return 515 if not back: 516 setcols() 517 reset_cursor() 518 is_tty = is_stdout_a_tty() 519 if is_tty: 520 writechar("\r", stderr = stderr) 521 522 if msg_header is None: 523 msg_header = MESSAGE_HEADER 524 header = color_func(msg_header) 525 526 _std_write(header, stderr = stderr) 527 _std_write(msg, stderr = stderr) 528 if not back: 529 _std_write(end, stderr = stderr) 530 531 if back and (not is_tty): 532 # in this way files are properly written 533 writechar("\n", stderr = stderr) 534 if flush: 535 _flush_stdouterr()
536 554 571 589 610
611 -def writechar(chars, stderr = False):
612 """ 613 Write characters to stdout (will be moved from here). 614 615 @param chars: chars to write 616 @type chars: string 617 """ 618 if is_mute(): 619 return 620 obj = sys.stdout 621 if stderr: 622 obj = sys.stderr 623 try: 624 obj.write(chars) 625 obj.flush() 626 except IOError as e: 627 if e.errno == errno.EPIPE: 628 return 629 raise
630
631 -def readtext(request, password = False):
632 """ 633 Read text from stdin and return it (will be moved from here). 634 635 @param request: textual request to print 636 @type request: string 637 @keyword password: if you are requesting a password, set this to True 638 @type password: bool 639 @return: text read back from stdin 640 @rtype: string 641 @raise EOFError: if CTRL+D is pressed 642 """ 643 xterm_title(_("Entropy needs your attention")) 644 if password: 645 from getpass import getpass 646 try: 647 text = getpass(request+" ") 648 except UnicodeEncodeError: 649 text = getpass(request.encode('utf-8')+" ") 650 else: 651 try: 652 sys.stdout.write(request) 653 except UnicodeEncodeError: 654 sys.stdout.write(request.encode('utf-8')) 655 _flush_stdouterr() 656 text = _my_raw_input() 657 return text
658
659 -def _my_raw_input(txt = ''):
660 try: 661 import readline 662 except ImportError: 663 # not available? ignore 664 pass 665 666 if not txt: 667 txt = "" 668 if const_is_python3(): 669 try: 670 response = input(darkgreen(txt)) 671 except UnicodeEncodeError: 672 response = input(darkgreen(txt.encode('utf-8'))) 673 else: 674 try: 675 response = raw_input(darkgreen(txt)) 676 except UnicodeEncodeError: 677 response = raw_input(darkgreen(txt.encode('utf-8'))) 678 _flush_stdouterr() 679 680 # try to convert to unicode, because responses are stored that 681 # way, fix bug #2006. 682 if not const_isunicode(response): 683 try: 684 response = const_convert_to_unicode(response, enctype = "utf-8") 685 except (UnicodeDecodeError, UnicodeEncodeError): 686 # be fault tolerant, we just tried 687 pass 688 return response
689
690 -class TextInterface(object):
691 692 """ 693 TextInterface is a base class for handling the communication between 694 user and Entropy-based applications. 695 696 This class works for text-based applications, it must be inherited 697 from subclasses and its methods reimplemented to make Entropy working 698 on situations where a terminal is not used as UI (Graphical applications, 699 web-based interfaces, remote interfaces, etc). 700 701 Every part of Entropy is using the methods in this class to communicate 702 with the user, channel is bi-directional. 703 """ 704 705 OUTPUT_LOCK = threading.RLock() 706 707 @classmethod
708 - def output(cls, text, header = "", footer = "", back = False, 709 importance = 0, level = "info", count = None, percent = False):
710 711 """ 712 Text output print function. By default text is written to stdout. 713 714 @param text: text to write to stdout 715 @type text: string 716 @keyword header: text header (decoration?) 717 @type header: string 718 @keyword footer: text footer (decoration?) 719 @type footer: string 720 @keyword back: push back cursor to the beginning of the line 721 @type back: bool 722 @keyword importance: message importance (default valid values: 723 0, 1, 2, 3 724 @type importance: int 725 @keyword level: message type (default valid values: "info", "warning", 726 "error", "generic") 727 @type level: string 728 @keyword count: tuple of lengh 2, containing count information to make 729 function print something like "(10/100) doing stuff". In this case 730 tuple would be: (10, 100,) 731 @type count: tuple 732 @keyword percent: determine whether "count" argument should be printed 733 as percentual value (for values like (10, 100,), "(10%) doing stuff" 734 will be printed. 735 @keyword percent: bool 736 @return: None 737 @rtype: None 738 """ 739 740 if is_mute(): 741 return 742 743 _flush_stdouterr() 744 745 myfunc = print_info 746 if level == "warning": 747 myfunc = print_warning 748 elif level == "error": 749 myfunc = print_error 750 elif level == "generic": 751 myfunc = print_generic 752 753 count_str = "" 754 if count: 755 if len(count) > 1: 756 if percent: 757 percent_str = str(round((float(count[0])/count[1])*100, 1)) 758 count_str = " ("+percent_str+"%) " 759 else: 760 count_str = " (%s/%s) " % (red(str(count[0])), 761 blue(str(count[1])),) 762 763 with TextInterface.OUTPUT_LOCK: 764 myfunc(header+count_str+text+footer, back = back, flush = False) 765 _flush_stdouterr()
766 767 @classmethod
768 - def ask_question(cls, question, importance = 0, responses = None):
769 770 """ 771 Questions asking function. It asks the user to answer the question given 772 by choosing between a preset list of answers given by the "reposonses" 773 argument. 774 775 @param question: question text 776 @type question: string 777 @keyword importance: question importance (no default valid values) 778 @type importance: int 779 @keyword responses: list of valid answers which user has to choose from 780 @type responses: tuple or list 781 @return: None 782 @rtype: None 783 """ 784 785 if responses is None: 786 responses = (_("Yes"), _("No"),) 787 788 colours = [green, red, blue, darkgreen, darkred, darkblue, 789 brown, purple] 790 colours_len = len(colours) 791 792 try: 793 sys.stdout.write(question + " ") 794 except UnicodeEncodeError: 795 sys.stdout.write(question.encode('utf-8') + " ") 796 _flush_stdouterr() 797 798 try: 799 while True: 800 801 xterm_title(_("Entropy got a question for you")) 802 _flush_stdouterr() 803 answer_items = [colours[x % colours_len](responses[x]) \ 804 for x in range(len(responses))] 805 response = _my_raw_input("["+"/".join(answer_items)+"] ") 806 _flush_stdouterr() 807 808 for key in responses: 809 if response.upper() == key[:len(response)].upper(): 810 xterm_title_reset() 811 return key 812 _flush_stdouterr() 813 814 except (EOFError, KeyboardInterrupt): 815 msg = "%s.\n" % (_("Interrupted"),) 816 try: 817 sys.stdout.write(msg) 818 except UnicodeEncodeError: 819 sys.stdout.write(msg.encode("utf-8")) 820 xterm_title_reset() 821 raise KeyboardInterrupt() 822 823 xterm_title_reset() 824 _flush_stdouterr()
825 826 @classmethod
827 - def input_box(cls, title, input_parameters, cancel_button = True):
828 """ 829 Generic input box (form) creator and data collector. 830 831 @param title: input box title 832 @type title: string 833 @param input_parameters: list of properly formatted tuple items. 834 @type input_parameters: list 835 @keyword cancel_button: make possible to "cancel" the input request. 836 @type cancel_button: bool 837 @return: dict containing input box answers 838 @rtype: dict 839 840 input_parameters supported items: 841 842 [input id], [input text title], [input verification callback], [ 843 no text echo?] 844 ('identifier 1', 'input text 1', input_verification_callback, False) 845 846 ('item_3', ('checkbox', 'Checkbox option (boolean request) - please choose',), 847 input_verification_callback, True) 848 849 ('item_4', ('combo', ('Select your favorite option', ['option 1', 'option 2', 'option 3']),), 850 input_verification_callback, True) 851 852 ('item_4',('list',('Setup your list',['default list item 1', 'default list item 2']),), 853 input_verification_callback, True) 854 855 """ 856 results = {} 857 if title: 858 try: 859 sys.stdout.write(title + "\n") 860 except UnicodeEncodeError: 861 sys.stdout.write(title.encode('utf-8') + "\n") 862 _flush_stdouterr() 863 864 def option_chooser(option_data): 865 mydict = {} 866 counter = 1 867 option_text, option_list = option_data 868 cls.output(option_text) 869 for item in option_list: 870 mydict[counter] = item 871 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 872 cls.output(txt) 873 counter += 1 874 while True: 875 try: 876 if const_is_python3(): 877 myresult = const_convert_to_unicode( 878 readtext("%s: " % (_('Selected number'),)), 879 enctype = "utf-8") 880 else: 881 myresult = readtext( 882 "%s: " % (_('Selected number'),)).decode('utf-8') 883 except UnicodeDecodeError: 884 continue 885 except UnicodeEncodeError: 886 continue 887 try: 888 myresult = int(myresult) 889 except ValueError: 890 continue 891 selected = mydict.get(myresult) 892 if selected != None: 893 return myresult, selected
894 895 def list_editor(option_data, can_cancel, callback): 896 897 def selaction(): 898 cls.output('') 899 cls.output(darkred(_("Please select an option"))) 900 if can_cancel: 901 cls.output(" ("+blue("-1")+") "+darkred(_("Discard all"))) 902 cls.output(" ("+blue("0")+") "+darkgreen(_("Confirm"))) 903 cls.output(" ("+blue("1")+") "+brown(_("Add item"))) 904 cls.output(" ("+blue("2")+") "+brown(_("Edit item"))) 905 cls.output(" ("+blue("3")+") "+darkblue(_("Remove item"))) 906 cls.output(" ("+blue("4")+") "+darkgreen(_("Show current list"))) 907 # wait user interaction 908 cls.output('') 909 try: 910 action = readtext(darkgreen(_("Your choice (type a number and press enter):"))+" ") 911 except UnicodeDecodeError: 912 return '' 913 return action
914 915 mydict = {} 916 counter = 1 917 valid_actions = [0, 1, 2, 3, 4] 918 if can_cancel: 919 valid_actions.insert(0, -1) 920 option_text, option_list = option_data 921 txt = "%s:" % (blue(option_text),) 922 cls.output(txt) 923 924 for item in option_list: 925 mydict[counter] = item 926 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 927 cls.output(txt) 928 counter += 1 929 930 def show_current_list(): 931 for key in sorted(mydict): 932 txt = "[%s] %s" % (darkgreen(str(key)), blue(mydict[key]),) 933 cls.output(txt) 934 935 while True: 936 try: 937 sel_action = selaction() 938 if not sel_action: 939 show_current_list() 940 action = int(sel_action) 941 except (ValueError, TypeError,): 942 cls.output(_("You don't have typed a number."), level = "warning") 943 continue 944 if action not in valid_actions: 945 cls.output(_("Invalid action."), level = "warning") 946 continue 947 if action == -1: 948 raise KeyboardInterrupt() 949 elif action == 0: 950 break 951 elif action == 1: # add item 952 while True: 953 try: 954 try: 955 s_el = readtext(darkred(_("String to add (-1 to go back):"))+" ") 956 except UnicodeDecodeError: 957 raise ValueError() 958 if s_el == "-1": 959 break 960 if not callback(s_el): 961 raise ValueError() 962 mydict[counter] = s_el 963 counter += 1 964 except (ValueError,): 965 cls.output(_("Invalid string."), level = "warning") 966 continue 967 break 968 show_current_list() 969 continue 970 elif action == 2: # edit item 971 while True: 972 try: 973 edit_msg = _("Element number to edit (-1 to go back):") 974 try: 975 s_el = int(readtext(darkred(edit_msg)+" ")) 976 except UnicodeDecodeError: 977 raise ValueError() 978 if s_el == -1: 979 break 980 if s_el not in mydict: 981 raise ValueError() 982 try: 983 new_s_val = readtext("[%s: %s] %s " % ( 984 _("old"), mydict[s_el], _("new value:"),) 985 ) 986 except UnicodeDecodeError: 987 new_s_val = '' 988 if not callback(new_s_val): 989 raise ValueError() 990 mydict[s_el] = new_s_val[:] 991 except (ValueError, TypeError,): 992 cls.output(_("Invalid element."), level = "warning") 993 continue 994 break 995 show_current_list() 996 continue 997 elif action == 3: # remove item 998 while True: 999 try: 1000 try: 1001 s_el = int(readtext(darkred(_("Element number to remove (-1 to go back):"))+" ")) 1002 except UnicodeDecodeError: 1003 raise ValueError() 1004 if s_el == -1: 1005 break 1006 if s_el not in mydict: 1007 raise ValueError() 1008 del mydict[s_el] 1009 except (ValueError, TypeError,): 1010 cls.output(_("Invalid element."), level = "warning") 1011 continue 1012 break 1013 show_current_list() 1014 continue 1015 elif action == 4: # show current list 1016 show_current_list() 1017 continue 1018 break 1019 1020 mylist = [mydict[x] for x in sorted(mydict)] 1021 return mylist 1022 1023 for identifier, input_text, callback, password in input_parameters: 1024 while True: 1025 use_cb = True 1026 try: 1027 if isinstance(input_text, tuple): 1028 myresult = False 1029 input_type, data = input_text 1030 if input_type == "checkbox": 1031 answer = cls.ask_question(data) 1032 if answer == _("Yes"): 1033 myresult = True 1034 elif input_type == "combo": 1035 myresult = option_chooser(data) 1036 elif input_type == "list": 1037 use_cb = False 1038 myresult = list_editor(data, cancel_button, callback) 1039 else: 1040 while True: 1041 try: 1042 myresult = readtext(input_text+": ", password = password) 1043 if not const_is_python3(): 1044 myresult = myresult.decode("utf-8") 1045 except UnicodeDecodeError: 1046 continue 1047 break 1048 except (KeyboardInterrupt, EOFError,): 1049 if not cancel_button: # use with care 1050 continue 1051 return None 1052 valid = True 1053 if use_cb: 1054 valid = callback(myresult) 1055 if valid: 1056 results[identifier] = myresult 1057 break 1058 return results 1059 1060 @classmethod
1061 - def edit_file(cls, file_path):
1062 """ 1063 Open a file editor on given file path (file_path). 1064 1065 @param file_path: path to a writeable file 1066 @type file_path: string 1067 @return: True for successful edit, False otherwise 1068 @rtype: bool 1069 """ 1070 editor = os.getenv("EDITOR", "/bin/nano") 1071 return subprocess.call((editor, file_path)) == 0
1072 1073 @classmethod
1074 - def set_title(cls, title):
1075 """ 1076 Set application title. 1077 1078 @param title: new application title 1079 @type title: string 1080 """ 1081 xterm_title(title)
1082