summaryrefslogtreecommitdiffstats
path: root/Mac/Tools/IDE/PyInteractive.py
blob: dc75e4b3e97b40a48870bb752d8c043b78d21e44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import string
import sys
import traceback


try:
	sys.ps1
except AttributeError:
	sys.ps1 = ">>> "
try:
	sys.ps2
except AttributeError:
	sys.ps2 = "... "


def print_exc(limit=None, file=None):
	if not file:
		file = sys.stderr
	# we're going to skip the outermost traceback object, we don't
	# want people to see the line which excecuted their code.
	tb = sys.exc_traceback
	if tb:
		tb = tb.tb_next
	try:
		sys.last_type = sys.exc_type
		sys.last_value = sys.exc_value
		sys.last_traceback = tb
		traceback.print_exception(sys.last_type, sys.last_value, 
					sys.last_traceback, limit, file)
	except:
		print '--- hola! ---'
		traceback.print_exception(sys.exc_type, sys.exc_value, 
					sys.exc_traceback, limit, file)


class PyInteractive:
	
	def __init__(self):
		self._pybuf = ""
	
	def executeline(self, stuff, out = None, env = None):
		if env is None:
			import __main__
			env = __main__.__dict__
		if out:
			saveerr, saveout = sys.stderr, sys.stdout
			sys.stderr = sys.stdout = out
		try:
			if self._pybuf:
				self._pybuf = self._pybuf + '\n' + stuff
			else:
				self._pybuf = stuff
			
			# Compile three times: as is, with \n, and with \n\n appended.
			# If it compiles as is, it's complete.  If it compiles with
			# one \n appended, we expect more.  If it doesn't compile
			# either way, we compare the error we get when compiling with
			# \n or \n\n appended.  If the errors are the same, the code
			# is broken.  But if the errors are different, we expect more.
			# Not intuitive; not even guaranteed to hold in future
			# releases; but this matches the compiler's behavior in Python
			# 1.4 and 1.5.
			err = err1 = err2 = None
			code = code1 = code2 = None
			
			# quickly get out of here when the line is 'empty' or is a comment
			stripped = string.strip(self._pybuf)
			if not stripped or stripped[0] == '#':
				self._pybuf = ''
				sys.stdout.write(sys.ps1)
				sys.stdout.flush()
				return
			
			try:
				code = compile(self._pybuf, "<input>", "single")
			except SyntaxError, err:
				pass
			except:
				# OverflowError. More?
				print_exc()
				self._pybuf = ""
				sys.stdout.write(sys.ps1)
				sys.stdout.flush()
				return
			
			try:
				code1 = compile(self._pybuf + "\n", "<input>", "single")
			except SyntaxError, err1:
				pass
			
			try:
				code2 = compile(self._pybuf + "\n\n", "<input>", "single")
			except SyntaxError, err2:
				pass
			
			if code:
				try:
					exec code in env
				except:
					print_exc()
				self._pybuf = ""
			elif code1:
				pass
			elif err1 == err2 or (not stuff and self._pybuf):
				print_exc()
				self._pybuf = ""
			if self._pybuf:
				sys.stdout.write(sys.ps2)
				sys.stdout.flush()
			else:
				sys.stdout.write(sys.ps1)
				sys.stdout.flush()
		finally:
			if out:
				sys.stderr, sys.stdout = saveerr, saveout