comparison cmd2.py @ 406:cc5c68e15a83

merged
author Catherine Devlin <catherine.devlin@gmail.com>
date Sun, 07 Nov 2010 09:20:33 -0500
parents 3bef4253cf1b be18c88a0fc8
children f5aa16a22b52
comparison
equal deleted inserted replaced
405:3bef4253cf1b 406:cc5c68e15a83
44 if sys.version_info[0] > 2: 44 if sys.version_info[0] > 2:
45 import pyparsing_py3 as pyparsing 45 import pyparsing_py3 as pyparsing
46 raw_input = input 46 raw_input = input
47 else: 47 else:
48 import pyparsing 48 import pyparsing
49 49
50 __version__ = '0.6.0' 50 __version__ = '0.6.2'
51 51
52 class OptionParser(optparse.OptionParser): 52 class OptionParser(optparse.OptionParser):
53 def exit(self, status=0, msg=None): 53 def exit(self, status=0, msg=None):
54 self.values._exit = True 54 self.values._exit = True
55 if msg: 55 if msg:
203 def get_paste_buffer(): 203 def get_paste_buffer():
204 xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 204 xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
205 return xclipproc.stdout.read() 205 return xclipproc.stdout.read()
206 def write_to_paste_buffer(txt): 206 def write_to_paste_buffer(txt):
207 xclipproc = subprocess.Popen('xclip -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 207 xclipproc = subprocess.Popen('xclip -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
208 xclipproc.stdin.write(txt) 208 xclipproc.stdin.write(txt.encode())
209 xclipproc.stdin.close() 209 xclipproc.stdin.close()
210 # but we want it in both the "primary" and "mouse" clipboards 210 # but we want it in both the "primary" and "mouse" clipboards
211 xclipproc = subprocess.Popen('xclip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 211 xclipproc = subprocess.Popen('xclip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
212 xclipproc.stdin.write(txt) 212 xclipproc.stdin.write(txt.encode())
213 xclipproc.stdin.close() 213 xclipproc.stdin.close()
214 else: 214 else:
215 def get_paste_buffer(*args): 215 def get_paste_buffer(*args):
216 raise OSError, pastebufferr % ('xclip', 'On Debian/Ubuntu, install with "sudo apt-get install xclip"') 216 raise OSError, pastebufferr % ('xclip', 'On Debian/Ubuntu, install with "sudo apt-get install xclip"')
217 write_to_paste_buffer = get_paste_buffer 217 write_to_paste_buffer = get_paste_buffer
397 timing Report execution times 397 timing Report execution times
398 abbrev Accept abbreviated commands 398 abbrev Accept abbreviated commands
399 ''') 399 ''')
400 400
401 def poutput(self, msg): 401 def poutput(self, msg):
402 '''Convenient shortcut for self.stdout.write(); adds newline if necessary.'''
402 if msg: 403 if msg:
403 self.stdout.write(msg) 404 self.stdout.write(msg)
404 if msg[-1] != '\n': 405 if msg[-1] != '\n':
405 self.stdout.write('\n') 406 self.stdout.write('\n')
406 def perror(self, errmsg, statement=None): 407 def perror(self, errmsg, statement=None):
699 pyparsing.Optional(fileName) + (pyparsing.stringEnd | '|') 700 pyparsing.Optional(fileName) + (pyparsing.stringEnd | '|')
700 self.inputParser.ignore(pyparsing.quotedString).ignore(self.commentGrammars).ignore(self.commentInProgress) 701 self.inputParser.ignore(pyparsing.quotedString).ignore(self.commentGrammars).ignore(self.commentInProgress)
701 702
702 def preparse(self, raw, **kwargs): 703 def preparse(self, raw, **kwargs):
703 return raw 704 return raw
704 705 def postparse(self, parseResult):
706 return parseResult
707
705 def parsed(self, raw, **kwargs): 708 def parsed(self, raw, **kwargs):
706 if isinstance(raw, ParsedString): 709 if isinstance(raw, ParsedString):
707 p = raw 710 p = raw
708 else: 711 else:
709 # preparse is an overridable hook; default makes no changes 712 # preparse is an overridable hook; default makes no changes
715 s = s.replace(shortcut, expansion + ' ', 1) 718 s = s.replace(shortcut, expansion + ' ', 1)
716 break 719 break
717 result = self.parser.parseString(s) 720 result = self.parser.parseString(s)
718 result['raw'] = raw 721 result['raw'] = raw
719 result['command'] = result.multilineCommand or result.command 722 result['command'] = result.multilineCommand or result.command
723 result = self.postparse(result)
720 p = ParsedString(result.args) 724 p = ParsedString(result.args)
721 p.parsed = result 725 p.parsed = result
722 p.parser = self.parsed 726 p.parser = self.parsed
723 for (key, val) in kwargs.items(): 727 for (key, val) in kwargs.items():
724 p.parsed[key] = val 728 p.parsed[key] = val
765 except Exception, e: 769 except Exception, e:
766 self.perror(str(e), statement) 770 self.perror(str(e), statement)
767 finally: 771 finally:
768 return self.postparsing_postcmd(stop) 772 return self.postparsing_postcmd(stop)
769 def complete_statement(self, line): 773 def complete_statement(self, line):
774 """Keep accepting lines of input until the command is complete."""
770 if (not line) or ( 775 if (not line) or (
771 not pyparsing.Or(self.commentGrammars). 776 not pyparsing.Or(self.commentGrammars).
772 setParseAction(lambda x: '').transformString(line)): 777 setParseAction(lambda x: '').transformString(line)):
773 raise EmptyStatement 778 raise EmptyStatement
774 statement = self.parsed(line) 779 statement = self.parsed(line)
785 self.kept_state = Statekeeper(self, ('stdout',)) 790 self.kept_state = Statekeeper(self, ('stdout',))
786 self.kept_sys = Statekeeper(sys, ('stdout',)) 791 self.kept_sys = Statekeeper(sys, ('stdout',))
787 self.redirect = subprocess.Popen(statement.parsed.pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 792 self.redirect = subprocess.Popen(statement.parsed.pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
788 sys.stdout = self.stdout = self.redirect.stdin 793 sys.stdout = self.stdout = self.redirect.stdin
789 elif statement.parsed.output: 794 elif statement.parsed.output:
795 if (not statement.parsed.outputTo) and (not can_clip):
796 self.perror('Cannot redirect to paste buffer; install ``xclip`` and re-run to enable')
797 return
790 self.kept_state = Statekeeper(self, ('stdout',)) 798 self.kept_state = Statekeeper(self, ('stdout',))
791 self.kept_sys = Statekeeper(sys, ('stdout',)) 799 self.kept_sys = Statekeeper(sys, ('stdout',))
792 if statement.parsed.outputTo: 800 if statement.parsed.outputTo:
793 mode = 'w' 801 mode = 'w'
794 if statement.parsed.output == '>>': 802 if statement.parsed.output == '>>':
795 mode = 'a' 803 mode = 'a'
796 sys.stdout = self.stdout = open(os.path.expanduser(statement.parsed.outputTo), mode) 804 sys.stdout = self.stdout = open(os.path.expanduser(statement.parsed.outputTo), mode)
797 else: 805 else:
798 sys.stdout = self.stdout = tempfile.TemporaryFile() 806 sys.stdout = self.stdout = tempfile.TemporaryFile(mode="w+")
799 if statement.parsed.output == '>>': 807 if statement.parsed.output == '>>':
800 self.stdout.write(get_paste_buffer()) 808 self.stdout.write(get_paste_buffer())
801 809
802 def restore_output(self, statement): 810 def restore_output(self, statement):
803 if self.kept_state: 811 if self.kept_state:
1380 """Tries to force a new value into the same type as the current.""" 1388 """Tries to force a new value into the same type as the current."""
1381 typ = type(current) 1389 typ = type(current)
1382 if typ == bool: 1390 if typ == bool:
1383 try: 1391 try:
1384 return bool(int(new)) 1392 return bool(int(new))
1385 except ValueError, TypeError: 1393 except (ValueError, TypeError):
1386 pass 1394 pass
1387 try: 1395 try:
1388 new = new.lower() 1396 new = new.lower()
1389 except: 1397 except:
1390 pass 1398 pass
1451 for fname in glob.glob(fileset): 1459 for fname in glob.glob(fileset):
1452 tfile = open(fname) 1460 tfile = open(fname)
1453 self.transcripts[fname] = iter(tfile.readlines()) 1461 self.transcripts[fname] = iter(tfile.readlines())
1454 tfile.close() 1462 tfile.close()
1455 if not len(self.transcripts): 1463 if not len(self.transcripts):
1456 raise StandardError, "No test files found - nothing to test." 1464 raise (StandardError,), "No test files found - nothing to test."
1457 def setUp(self): 1465 def setUp(self):
1458 if self.CmdApp: 1466 if self.CmdApp:
1459 self.outputTrap = OutputTrap() 1467 self.outputTrap = OutputTrap()
1460 self.cmdapp = self.CmdApp() 1468 self.cmdapp = self.CmdApp()
1461 self.fetchTranscripts() 1469 self.fetchTranscripts()
1472 anyWhitespace = re.compile(r'\s', re.DOTALL | re.MULTILINE) 1480 anyWhitespace = re.compile(r'\s', re.DOTALL | re.MULTILINE)
1473 def _test_transcript(self, fname, transcript): 1481 def _test_transcript(self, fname, transcript):
1474 lineNum = 0 1482 lineNum = 0
1475 try: 1483 try:
1476 line = transcript.next() 1484 line = transcript.next()
1485 lineNum += 1
1477 while True: 1486 while True:
1478 while not line.startswith(self.cmdapp.prompt): 1487 while not line.startswith(self.cmdapp.prompt):
1479 line = transcript.next() 1488 line = transcript.next()
1489 lineNum += 1
1480 command = [line[len(self.cmdapp.prompt):]] 1490 command = [line[len(self.cmdapp.prompt):]]
1481 line = transcript.next() 1491 line = transcript.next()
1482 while line.startswith(self.cmdapp.continuation_prompt): 1492 while line.startswith(self.cmdapp.continuation_prompt):
1483 command.append(line[len(self.cmdapp.continuation_prompt):]) 1493 command.append(line[len(self.cmdapp.continuation_prompt):])
1484 line = transcript.next() 1494 line = transcript.next()
1495 lineNum += 1
1485 command = ''.join(command) 1496 command = ''.join(command)
1486 stop = self.cmdapp.onecmd_plus_hooks(command) 1497 stop = self.cmdapp.onecmd_plus_hooks(command)
1487 #TODO: should act on ``stop`` 1498 #TODO: should act on ``stop``
1488 result = self.outputTrap.read() 1499 result = self.outputTrap.read()
1489 if line.startswith(self.cmdapp.prompt): 1500 if line.startswith(self.cmdapp.prompt):
1493 continue 1504 continue
1494 expected = [] 1505 expected = []
1495 while not line.startswith(self.cmdapp.prompt): 1506 while not line.startswith(self.cmdapp.prompt):
1496 expected.append(line) 1507 expected.append(line)
1497 line = transcript.next() 1508 line = transcript.next()
1509 lineNum += 1
1498 expected = ''.join(expected) 1510 expected = ''.join(expected)
1499 message = '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n'%\ 1511 message = '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n'%\
1500 (fname, lineNum, command, expected, result) 1512 (fname, lineNum, command, expected, result)
1501 expected = self.expectationParser.transformString(expected) 1513 expected = self.expectationParser.transformString(expected)
1502 # checking whitespace is a pain - let's skip it 1514 # checking whitespace is a pain - let's skip it
1503 expected = self.anyWhitespace.sub('', expected) 1515 expected = self.anyWhitespace.sub('', expected)
1504 result = self.anyWhitespace.sub('', result) 1516 result = self.anyWhitespace.sub('', result)
1505 self.assert_(re.match(expected, result, re.MULTILINE | re.DOTALL), message) 1517 self.assert_(re.match(expected, result, re.MULTILINE | re.DOTALL), message)
1506 except StopIteration: 1518 except StopIteration:
1507 pass 1519 message = 'Last %d lines never seen, beginning with\n%s' % (len(expected), expected[0])
1520 self.assert_(len(expected) < 3, message)
1508 def tearDown(self): 1521 def tearDown(self):
1509 if self.CmdApp: 1522 if self.CmdApp:
1510 self.outputTrap.tearDown() 1523 self.outputTrap.tearDown()
1511 1524
1512 if __name__ == '__main__': 1525 if __name__ == '__main__':