On Tue, Aug 14, 2018 at 3:21 PM Erik Bray <erik....@gmail.com> wrote:
>
> On Mon, Aug 13, 2018 at 7:07 PM Emmanuel Charpentier
> <emanuel.c...@gmail.com> wrote:
> >
> > Motivation : see this ask.sagemath.org question.
> > Tl;dr : I want to call sage from the R reticulate package in order to create mixed text/R/Sage documents.
> >
> > I am aware that Sagetex allows this, at least when using Sage's R in a \LaTeX document.
> > But this solution doesn't extend to noweb Markdown documents, which are more and more in demand (Web pages, ebooks, other interactive gadgets).
> > I have checked that the \LaTeX--> Markdown/whatever conversion currently doable with pandoc or similar tools is cumbersome to the extreme and/or loses a lot of information.
> >
> > Done so far : when used as the "Python" interpreter, Sage starts a Python session of its own interpreter (i. e. doesn't start the usual IPython session). The various environment variables are correctly defined.
> >
> > Thanks to Thierry Monteil, I have been able to create this Sage IPython session, with correct initialization (preparsing, imports, etc...). I have checked that this session can access R objects, and that the R session can access objects created in Sage.
> >
> > But this is insufficient :
> >
> > The Sage session does not (re-)starts automatically : one has to explicitly call IPython.embed(). Not a problem when tran manually ; problematic for the intended use (creating Sage code chunks in a noweb document).
> > To get back to R, you have to exit twice : from the IPython session then from the Python session. Again not a problem in interactive use, again a serious problem for the intended use.
> >
> > So the question is : how can one *replace* the Python REPL with Sage's ? A serious look at $SAGE_ROOT/src/sage/repl/ipython_extension.py wasn't specially enlightening...
> >
> > Any ideas ?
> >
> > [ Note that this answer is necessary to the "right" function, but not sufficient : the name of the Python object interfacing Python to the *calling* R session is, unfortunately "r". Which is the standard name we have picked for our *called* R interpreter... So some r-handling will be necessary from reticulate's side. Keeping the distinction between those may be necessary (e. g. : reusing old code...).
> > But I feel that asking for a patch has better chances if we "do our homework first", by solving *our* side of the problem *before* asking for help... ]
>
> Did you try my suggestion of just setting `use_python(/path/to/sage-ipython)`?
I'm not an R expert, so take with a grain of salt, but I spent a few
minutes reading the sources for reticulate and understanding how it
works,
and I don't think my above suggestion will help you much (nor
will most of the things you've tried).
It mostly just uses the interpreter path passed to use_python() to run
a little Python script that it then uses to determine a few more
things about the Python in question. Most importantly, it calls that
Python to determine the correct libpython shared library to use. It
then dlopens() the appropriate libpython, and from then on uses the
Python C API to initialize and communicate with a Python interpreter
(including bringing up the REPL, as necessary). Most Python code you
send through it is just passed directly to the Python interpreter
through the C API, so of course things like the Sage preparsing won't
work, etc.
Sure, you can drop into an interactive REPL, and call IPython.embed(),
and you'll get an IPython REPL and all the trappings thereof, but that
will only work for interactive use.
I noticed that reticulate also comes with helper functions like
use_virtualenv() and use_condaenv(). It might be useful to add a
similar use_sageenv(), which would set the appropriate environment
variables (SAGE_ROOT, etc.) and tell reticulate to use Sage's Python.
But then to get things like preparsing working you'll have to write
wrappers around most of reticulate's other APIs as well.
They might
also be amenable to a patch. It might not even need to be
Sage-specific; for example maybe it would be good to have an interface
transforming inputs prior to passing to the Python interpreter (as
IPython provides, allowing us to slip in Sage's preparse()).
Perhaps if it were refactored into a class and aspects of it were made
more customizable I could see how it could be useful in conjunction
with other packages. But it's still not that useful at all outside
the context of an IPython interpreter that has the necessary hooks to
transform code before passing it to the Python interpreter.
Now, if the interpreter had a *built in* hook that would allow
arbitrary preparsing on inputs that would be very powerful (and
dangerous).
But short of that, any program that wants to be able to
run Python statements (i.e. in something like reticulate, or any other
program that wraps a Python interpreter) has to provide its own
interface for pre-processing inputs to the Python interpreter, and
that's fine too.
>>> from sage.all import *>>> exec(preparse(r"""
... a = 2^3
... print a
... """))
8
>>> a
8
>>> exit
> py$a
8or also:
>>> load("some.sage") #I believe all sage power is available in load() but not all in exec(preparse()).