Ask Your Question
1

REPL-like output

asked 2019-04-20 22:10:21 -0500

dsejas gravatar image

updated 2019-04-20 22:20:40 -0500

Hello, Sage Community.

If I run the sage REPL in a terminal, and execute something like

for i in range(4):
    print(i^2)

then we all know that Sage prints

0
1
4
9

In this case, I could create a class to intercept standard output to a variable, like:

class verboseBuffer:
    def __init__(self):
        self.buffer = ''
    def write(self, s):
        self.buffer += s

Then I just make

_verbOut_ = verboseBuffer()
sys.stdout = _verbOut_

and if I run the first chunk of code, then the integers will be stored in _verbOut_.buffer, instead of being printed to standard output as before. I finally can do

sys.stdout = sys.__stdout__
print(_verbOut_.buffer)

and this prints the contents of _verbOut_.buffer, i.e., the list at the beginning.

Now consider the same loop without the print:

for i in range(4):
    i^2

Executed in the REPL, Sage will print exactly the same as before (even if I haven't specified to print), and I could do the same thing to redirect the standard output to a variable.

Now, on the other hand, I have a huge file for which I would like to print everything in the same way it is printed in the REPL. I can't add print to every single part of the file, so I have tried to redirect output to a variable as before, and print it in the last line. The problem is that, things like the last chunk of code, without an explicit print won't be stored in _verbOut_.buffer at the end of the execution.

My questions are:

  1. Why does the Sage REPL prints all computations not assigned to a variable, like the i^2 in the loop, but that doesn't happen if the code is in a file?
  2. How can I obtain a REPL-like output without having to add print to everything in my long file?
edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
1

answered 2019-04-21 19:55:00 -0500

dsejas gravatar image

Hello. Inspired by @slelievre's answer, I have come up with a way to do what I wanted. However, it seems a little cumbersome, so I am not considering it a 100% of an answer (although I am posting it as one). If somebody can improve this, please, your help is welcome!

I use the following code in a file called test.sage:

from sage.repl.interpreter import SageTerminalApp
app = SageTerminalApp.instance()

To my understanding, this creates some sort of instance of an interactive Sage session. If I add the following line:

app.initialize()

and run sage test.sage, then the Sage prompt appears on my terminal, but it's not from the sage part of the command, but the contents of the file created this Sage session.

However, since I don't want to interact with Sage, I have used the app.code_to_run. For example, if I want to execute the

for i in range(4):
    i^2

of my question, including the standard output redirection, I just add

app.code_to_run = r"""
class verboseBuffer:
def __init__(self):
    self.buffer = ''
def write(self, s):
    self.buffer += s
_verbOut_ = verboseBuffer()
sys.stdout = _verbOut_
for i in range(4):
    i^2
sys.stdout = sys.__stdout__
print(_verbOut_.buffer)"""

right before app.initialize(). Now, if I run sage test.sage, the code is executed, and the session is immediately finished, without the prompt appearing (i.e., it is not an interactive session!).

The good thing is the following: Notice that I didn't use print(i^2)? Well, even so, the results of this line are passed to standard output (which is catch on _verbOut_.buffer in this case, of course), exactly as happens in the interactive terminal. To see this for yourselves, just delete the line print(_verbOut_.buffer) and execute the file again.

In summary: I can now execute Sage code in a file as if it were manually introduced to the sage terminal, which is a leap forward! But I don't completely understand my own code, so I don't know if this the best path to procedd, and I think there is space for improvement and perfectioning.

edit flag offensive delete link more
1

answered 2019-04-21 10:16:21 -0500

slelievre gravatar image

updated 2019-04-21 10:45:43 -0500

Not sure this is what you are asking, but this question might be related:

and the answer there is to do:

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'

and then Jupyter cells will print out all the computed results in the cell, not only the last.

edit flag offensive delete link more
1

answered 2019-04-21 02:18:12 -0500

nbruin gravatar image

1: That's what Python and IPython do. However if you do

def loop():
    for i in range(4):
        i^2
loop()

then even at the REPL prompt you won't see output. The REPL doesn't get to execute the individual commands and print their return values for you, because the commands are already packaged up in a function.

2: If your input is in "long_input_file.sage" you could use

sage <long_input_file.sage

or

cat long_input_file.sage | sage

then your input is still entered into sage "through the REPL": by redirecting STDIN. (assuming a unix-type command line environment)

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2019-04-20 22:10:21 -0500

Seen: 87 times

Last updated: Apr 21