Ask Your Question

Is there a way to start a Sage session from a session of its Python interpreter ?

asked 2018-08-05 14:11:20 -0500

Emmanuel Charpentier gravatar image

updated 2018-08-13 12:11:26 -0500

Yes, I know its sounds silly. But there is a point...

The R library reticulate allows to use a persistent Python session from a R session. One of its main uses is to allow to use Python code as well as R code in the creation of reports or papers. This is really useful for everyday statistics use...

One can do similar things with Sage and SageTeX, but using R and R objects is a bit awkward. Furthermore, the R tools offer abilities not easily emulated from within Sage. One can create composite documents using R facilities for R code (knitr) and SageTeX (or PythonTeX, better maintained nowadays) for supporting Sage code ; but usng such composite documents is a bit awkward : passing from the source to the compiled document entails :

  • knit the R code of the .Rnw file, getting a .tex file ;
  • \LaTeX the .tex file at least once ;
  • sage (or pythontex) the resultant file
  • re-\LaTeX the .tex file at least once.

This is a bit hard to automate... The same thing applies with aggravation to Markdown texts : the Sage chunks have to be wrapped in \LaTeX-only chunks, and the sage steps have to be done manually from the command line (or from emacs, which amounts to the same thing).

The availability of a persistent Sage session would solve the problem.

A small trial using Sage's R (launched by sage -R) shows that this is almost possible :

> library(reticulate)
> use_python("/usr/local/sage-8/sage") ## This is the main Sage script file
> repl_python()
Python 2.7.15 (/usr/local/sage-8/sage)
Reticulate 1.10 REPL -- A Python interpreter in R.
>>> 2^3

We are in python, no preparsing takes place.

>>> arctan
NameError: name 'arctan' is not defined

arctan is not defined : noting Sage-specific is known.

>>> from sage.all import *
>>> arctan

The import succeeded.

>>> x
NameError: name 'x' is not defined

But the (default) definition of x as a symbolic variable has not been done.

>>> var("x")
>>> x
>>> foo=arctan(x).integrate(x)
>>> exit

We are back to R, from which we can access toplevel objects in the Python session :

> py$foo
x*arctan(x) - 1/2*log(x^2 + 1)
> py$latex(py$foo)
x \arctan\left(x\right) - \frac{1}{2} \, \log\left(x^{2} + 1\right)
> py_to_r(py$latex(py$foo))
x \arctan\left(x\right) - \frac{1}{2} \, \log\left(x^{2} + 1\right)

Not a "standard" R characer vector :

> class(py_to_r(py$latex(py$foo)))
[1] "sage.misc.latex.LatexExpr" "python.builtin.str"       
[3] "python.builtin.basestring" "python.builtin.object"

But it can be used as such :

> paste("** ",py$latex(py$foo)," **", sep="")
[1] "** x \\arctan\\left(x\\right) - \\frac{1}{2} \\, \\log\\left(x^{2} + 1\\right) **"

Now, it is possible to insert the loading of a Python module before the launch of the Python REPL : From the doc of repl_python :

module: An (optional) Python module to be imported before the REPL is launched.

So the question is : is it possible to write a module correctly importing sage.all AND whose __init__ function would replace Python's REPL by Sage's ?

ISTR that a few years ago, before the introduction of Sage's Jupyter notebook, such tricks were used in Jupyter to start a Sage session (complete with preparser) from an "ordinary" Jupyter notebook. But for the life of me, I haven't been able to retrieve the relevant pages...

Any thoughts ?

EDIT : A bit of googling using the former name "IPython notebook" led me to this StackOverflow question, whose first answer, by no other than William Stein, tells the user that using %load_ext sage would start Sage from a (conventient) IPython session. Indeed :

charpent@asus16-ec:~$ sage -ipython
Python 2.7.15 (default, May 19 2018, 18:46:27) 
Type "copyright", "credits" or "license" for more information.

IPython 5.5.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: 2^3
Out[1]: 1

So we are in Python, no preprocessing

In [2]: x
NameError                                 Traceback (most recent call last)
<ipython-input-2-6fcf9dfbd479> in <module>()
----> 1 x

NameError: name 'x' is not defined

x not defined.

In [3]: %load_ext sage

In [4]: 2^3
Out[4]: 8

We are in Sage !

In [5]: x
Out[5]: x

x has been defined

In [6]: quit()
Exiting Sage (CPU time 0m0.13s, Wall time 0m14.53s).

So this sage notebook extension to IPython still exists, and does what I want. Its dissection should give me what I need to write my helper module.

But for the life of me, I have been unable to divine its source. what is it, and where is it ?

EDIT on 2018-08-13 : that source is in $SAGE_ROOT/src/sage/repl/, but is insufficient (to me !) to build a solution. Question re-asked on sage-devel in order to reach new eyeballs...

edit retag flag offensive close merge delete


Have you tried running sage-ipython instead?

Iguananaut gravatar imageIguananaut ( 2018-08-06 10:33:20 -0500 )edit

How about wrapping commands in sage_eval(...)? That should give you access to the preparser from Python.

rburing gravatar imagerburing ( 2018-08-13 16:42:49 -0500 )edit

@rburing : doesn't work. From R :

> S='sage_eval("foo=2^3")'
> py_run_string(S)
Error in py_run_string_impl(code, local, convert) : 
  SyntaxError: invalid syntax (<string>, line 1)

Detailed traceback: 
  File "<string>", line 1, in <module>
  File "/usr/local/sage-8/local/lib/python2.7/site-packages/sage/misc/", line 203, in sage_eval
    return eval(source, sage.all.__dict__, locals)

I think that sage_eval doesn't find the "right" Python eval...

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 2018-08-14 09:00:23 -0500 )edit

eval only takes an expression as input (or a pre-compiled code object). An assignment is a statement in Python, not an expression, so trying to eval (or sage_eval) an assignment statement will result in a SyntaxError.

Iguananaut gravatar imageIguananaut ( 2018-08-14 13:11:31 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2018-08-06 05:56:38 -0500

tmonteil gravatar image

updated 2018-08-06 09:01:14 -0500

The source can be found in the SAGE_ROOT/src/sage/repl/ directory, in particular

EDIT : if you want to run ipython interpreter from Python's one, (and then Sage the way you suggested), you can do:

>>> import IPython
>>> IPython.embed()
Python 2.7.15 (default, Jul 23 2018, 10:39:00) 
Type "copyright", "credits" or "license" for more information.

IPython 5.5.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %load_ext sage

In [2]: 2^2
Out[2]: 4

In [3]: sin(x)
Out[3]: sin(x)
edit flag offensive delete link more


Thanks ! But I have trouble finding what I should call to init the Sage session. I'm a bit out of my bepth here...

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 2018-08-06 08:27:39 -0500 )edit

I edited my answer.

tmonteil gravatar imagetmonteil ( 2018-08-06 08:59:35 -0500 )edit

That works. But it is not enough for what I want to do.

The point of reticulate is that it creates a permanent Python session, that can be left (with exit) and resumed at a later point, without loss of the previous work (which can be accessed from R, BTW : that's another big part of the point !).

When one launches an IPython session, all works. However,when one resumes this session, one lands in a Python session ; therefore one has to re-IPython.embed(), and there, the session is a Python session : 2^3 returns 1 no matter what. Even reload_ext sage won't re-establish the pre-parsing.

What I want to do is to establish all the specifics of a Sage terminal session without launching an IPython sesion. That means importing sage.all, establish pre-parsing, etc...

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 2018-08-06 11:17:44 -0500 )edit

Meanwhile there is no solution:

>>> exec(preparse(r"""
... a = 2^3
... print a
... """))
>>> a
>>> exit
> py$a

or also:

>>> load("some.sage")
Pedro gravatar imagePedro ( 2018-08-13 19:43:48 -0500 )edit

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


Asked: 2018-08-05 14:11:20 -0500

Seen: 83 times

Last updated: Aug 13