Skip to content

Commit d408ba1

Browse files
committed
Python Session: improved eval
1 parent 5cb5a95 commit d408ba1

File tree

4 files changed

+40
-30
lines changed

4 files changed

+40
-30
lines changed

plugins/python/doc/python-limitations.en.tm

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<TeXmacs|1.99.2>
1+
<TeXmacs|1.99.12>
22

3-
<style|tmdoc>
3+
<style|<tuple|tmdoc|old-spacing|old-dots>>
44

55
<\body>
66
<tmdoc-title|Limitations and things to do>
@@ -12,9 +12,6 @@
1212

1313
<item>The (utterly useless) help window should be a help browser, with
1414
links, history, etc.
15-
16-
<item>Evaluation of multiple expressions should return (at least) the
17-
value of the last one, as the <name|Python> <abbr|REPL> does.
1815
</itemize>
1916

2017
<tmdoc-copyright|2004, 2014|Adrián Soto|Miguel de Benito Delgado>

plugins/tmpy/postscript.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class PSOutDummy:
2121
We return an instance of this class to avoid output after
2222
evaluation in the TeXmacs plugin of ps_out."""
2323

24+
def __init__(self, data):
25+
self.content = data
26+
2427
def __str__(self):
2528
"""Return an empty string for compose_output()"""
2629
return ''
@@ -29,7 +32,7 @@ def __repr__(self):
2932
return 'PSOutDummy'
3033

3134

32-
def ps_out(out):
35+
def ps_out (out):
3336
"""Outputs PostScript within TeXmacs.
3437
3538
According the the type of the argument the following
@@ -77,5 +80,4 @@ def ps_out(out):
7780
elif 'read' in dir(out):
7881
data = out.read()
7982

80-
flush_ps(texmacs_escape(data).decode())
81-
return PSOutDummy()
83+
return PSOutDummy(texmacs_escape(data).decode())

plugins/tmpy/protocol.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def data_end():
3232
os.sys.stdout.flush()
3333

3434

35-
def texmacs_escape(data):
35+
def texmacs_escape (data):
3636
return data.replace(DATA_BEGIN.encode(), (DATA_ESCAPE + DATA_BEGIN).encode()) \
3737
.replace(DATA_END.encode(), (DATA_ESCAPE + DATA_END).encode())
3838

plugins/tmpy/session/tm_python.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525

2626
import traceback
2727
import string
28+
import ast
2829
from inspect import ismodule, getsource, getsourcefile
2930
from tmpy.compat import py_ver
3031
from tmpy.capture import CaptureStdout
31-
from tmpy.postscript import ps_out
32+
from tmpy.postscript import ps_out, PSOutDummy
3233
from tmpy.completion import parse_complete_command, complete
3334
from tmpy.protocol import *
3435

@@ -37,25 +38,23 @@
3738
exit (-1)
3839

3940
# import logging as log
40-
# log.basicConfig(filename='/tmp/tm_python.log',level=log.DEBUG)
41-
def compose_output (data):
41+
# log.basicConfig(filename='/tmp/tm_python.log',level=log.INFO)
42+
43+
def flush_output (data):
4244
"""Do some parsing on the output according to its type.
4345
4446
Non printable characters in unicode strings are escaped
4547
and objects of type None are not printed (so that procedure calls,
4648
as opposed to function calls, don't produce any output)."""
4749

48-
if isinstance(data, str):
49-
data2 = r''
50-
for c in data:
51-
if c not in string.printable:
52-
data2 += '\\x%x' % ord(c)
53-
else:
54-
data2 += c
55-
data = data2
56-
if data is None:
57-
data = ''
58-
return str(data).strip()
50+
if (data is None):
51+
flush_verbatim ("")
52+
return
53+
54+
if isinstance (data, PSOutDummy):
55+
flush_ps (data.content)
56+
else:
57+
flush_verbatim (str(data).strip())
5958

6059
def as_scm_string (text):
6160
return '"%s"' % text.replace('\\', '\\\\').replace('"', '\\"')
@@ -85,6 +84,18 @@ def compile_help (text):
8584

8685
return dict (map (lambda k_v: (k_v[0], as_scm_string (k_v[1])), out.items()))
8786

87+
88+
def my_eval (code, p_globals):
89+
'''Execute a script and return the value of the last expression'''
90+
91+
block = ast.parse(code, mode='exec')
92+
if len(block.body) > 1 and isinstance(block.body[-1], ast.Expr):
93+
last = ast.Expression(block.body.pop().value)
94+
exec(compile(block, '<string>', mode='exec'), p_globals)
95+
return eval(compile(last, '<string>', mode='eval'), p_globals)
96+
else:
97+
return eval(code, p_globals)
98+
8899
__version__ = '3.0'
89100
__author__ = 'Ero Carrera, Adrian Soto, Miguel de Benito Delgado, Darcy Shen'
90101
my_globals = {}
@@ -115,7 +126,7 @@ def compile_help (text):
115126
"Please see the documentation in Help -> Plugins -> Python")
116127
flush_prompt (">>> ")
117128
while True:
118-
line = input ()
129+
line= input ()
119130
if not line:
120131
continue
121132
if line[0] == DATA_COMMAND:
@@ -125,22 +136,22 @@ def compile_help (text):
125136
continue
126137
elif line.endswith('?') and not line.strip().startswith('#'):
127138
if len(line) > 1:
128-
out = compile_help (line[:-1])
139+
out= compile_help (line[:-1])
129140
flush_command ('(tmpy-open-help %s %s %s)' %
130141
(out["help"], out["src"], out["file"]))
131142
else:
132143
flush_verbatim ('Type a name before the "?" to see the help')
133144
continue
134145
else:
135-
lines = [line]
146+
lines= [line]
136147
while line != "<EOF>":
137-
line = input ()
148+
line= input ()
138149
if line == '':
139150
continue
140151
lines.append (line)
141152
text = '\n'.join (lines[:-1])
142153
try: # Is it an expression?
143-
result = eval (text, my_globals)
154+
result= my_eval (text, my_globals)
144155
except:
145-
result = CaptureStdout.capture (text, my_globals, "tm_python")
146-
flush_verbatim (compose_output(result))
156+
result= CaptureStdout.capture (text, my_globals, "tm_python")
157+
flush_output (result)

0 commit comments

Comments
 (0)