Is there a way to run Python from within Mathematica?

I know there is some support for running Mathematica from Python, but is there any way to do the reverse. For example, to import some Python classes and use them in Mathematica?

-
related: mathematica.stackexchange.com/q/1894/5 (I don't know enough to tell if it's a dupe or not) – R. M. Dec 3 '12 at 21:59
@rm-rf: Different: that relies on .NET. – raxacoricofallapatorius Dec 3 '12 at 22:01
Google Pythonika – Mark McClure Dec 3 '12 at 22:19
@Jens He says he wants "to import some Python classes and use them in Mathematica". That's exactly what Pythonika does. I've used it to run sage from Mathematica. One of the dumbest things I've ever done, but I did it: facstaff.unca.edu/mcmcclur/Mathematica/Sage – Mark McClure Dec 3 '12 at 22:40
@MarkMcClure: Pythonica seems not to be a viable solution. I can't get it to load (0S X 10.8.2, Python 2.7.2, Mathematica 9.0). Are there any alternatives? – raxacoricofallapatorius Dec 12 '12 at 1:52

If all you want is to invoke Python scripts and use the output they generate in Mathematica, then simply

pythonOutput = Import["!python fullpathtoscript/your_scipt.py --some_opt arg arg ...", "String"];


is sufficient.

-
Commands like this don't work at all for me in Mathematica 10.0.1. – Mike Nov 21 '14 at 3:44
It works for me in Mathematica 10.0.2.0. – ThomasH Apr 6 '15 at 18:55
@ThomasH: Can you give me a specific example of something that works that I can try. It doesn't even work for me anymore (10.0.2.0). – raxacoricofallapatorius Apr 6 '15 at 20:24
For a MWE, I made a file in my home directory called test.py containing "print('hello world')", then in Mathematica (also pointed at my home directory by default), 'Import["!python test.py","String"]' produces the string "hello world". I have a simple but slightly more complicated example I can point you to on github if you'd like. – ThomasH Apr 9 '15 at 17:14

Here is a more robust solution using Process:

Clear[runPython];
runPython::badCommand  ="Python code failed to run with message StandardError";
$pyimports="from random import randint "; runPython[str_String, imports_:$pyimports] := Module[
{pyscrpt = ToString[$pyimports<>str, CharacterEncoding->"ASCII"], file=CreateTemporary[], res}, Export[file,pyscrpt,"Text"]; res = RunProcess[{"/anaconda/bin/python",file}]; DeleteFile[file]; If[res["ExitCode"]!=0, Return @ Failure["badCommand",<|"MessageTemplate" :> runPython::badCommand,"MessageParameters"-> <|"Message" -> res["StandardError"]|>|>], Return @ ImportString @ res["StandardOutput"] ] ]  I had to use anaconda's python executable - Mathematica was crashing the system's python runtime. - Here is an approach that works on Mac OS X or unix-like systems without the need to explicitly create any temp directory: code = "print \\\"hello, starting\\\" for i in [1,2,3]: \t print i*i " (* ==> "print \\\"hello, starting\\\" for i in [1,2,3]: print i*i " *) RunProcess[$SystemShell, "StandardOutput",
"printf \"" <> code <> "\" | python
exit
"]

(* ==>
"hello, starting
1
4
9
"
*)


First, I define the string containing the Python code. I included a test message to illustrate how you have to escape the quotation marks using \\\" inside the string, because it's going to be passed into a printf command on the shell command line. THat printf is subsequently piped into python. Note that I didn't have to specify the path because it's found from the SystemShell environment.

The interaction with Mathematica takes place via RunProcess, and the standard output of the Python script is directly captured into Mathematica. Again, it's not necessary to bother with any temporary files in this approach.

-
Can you contrast this with the Import approach? Is it just that it avoids using an existing script? FWIW, I'd never write the Python code in the Mathematica environment: the code editing tools are just too poor. – raxacoricofallapatorius Apr 5 '15 at 14:14
Also, can you show how it would work with an existing script? – raxacoricofallapatorius Apr 5 '15 at 14:21
@raxacoricofallapatorius Yes, my main point is to have the script and everything it needs completely inside Mathematica. If you already have an existing script outside Mathematica, then it's not a real two-way interaction, I'd say. But what to do with an existing script specifically would depend on the application. I can't think of anything general to say about that, except that it would be possible, e.g., to pass arguments to it using my approach. An important advantage of my approach is, however, that it makes the entire process portable: you can email the notebook without attachments. – Jens Apr 5 '15 at 16:13
Yes; also, it looks like the approach I had no longer works. – raxacoricofallapatorius Apr 5 '15 at 18:19
Oh well, that's just a formatting error when I manually tried to put the python string into a form that looks right in the code cell above. One extra space crept in, and that kills python. I fixed it. If it still doesn't work, it could be dependent on the OS and version of Mathematica. This RunProcess command doesn't work in earlier versions... by the way, another way of interacting with python is through the clipboard on Mac. But I don't know what your actual goal is, so I'll skip that for now. – Jens Apr 5 '15 at 21:19

Building off of @M.R.'s idea, it is possible to set up an interactive python shell using StartProcess as opposed to RunProcess, allowing for much more flexible connectivity between Python and Wolfram without as much overhead. In it's simplest form, one can open a connection, interact with it, and close it using the following example:

path = "e:\\Programs\\python27\\python"; (*insert OS-appropriate path \
to python*)
p = StartProcess[{path, "-i"}]; (*the'-i' argument is important*)
cmd = "print 'hello'"; (*or any valid python expression*)
Pause[1]; (* important!!! *)
WriteLine[p, cmd];
KillProcess@p;


Pausing after the StartProcess call is important in order to avoid the cmd being sent to the python interpreter before it has finished loading. A much shorter pause can be used on faster computers.

I've put together a short package to streamline python interactivity. The version I've posted below also reads the python shell text (which is delivered on stderr) and prints that to the Message window if the FrontEnd is active or simply Prints it if the command line is being used. It works nicely with simple commands pcmd@"print 'hello'" and I've had success with some sophisticated operations such as web scraping with Splinter and BeautifulSoup. It coughs when trying to use something like Tkinter, but it just doesn't work as opposed to throwing some form of error, making it a bit difficult to debug.

BeginPackage["wlPython"];

$pythonprocess = Null;$pythonpath = "e:\\Programs\\python27\\python";
$pythonpause = 0.250; (* Pause in seconds to receive error information *) startPython::usage = "Starts the python process"; endPython::usage = "Ends the python process"; pcmd::usage = "issue a python command"; (* Check for FrontEnd and set as appropriate, can be overridden *)$pyfrontend = $FrontEnd=!=Null; Begin["Private"]; Clear[startPython] startPython[path_:$pythonpath]:=Module[{err},
$pythonprocess = StartProcess[{path,"-i"}]; wlPythonpyerrcheck[];$pythonprocess
]

Clear[endPython]
endPython[process_:Unevaluated@$pythonprocess]:=Module[{}, KillProcess@Evaluate@process; NotebookWrite[MessagesNotebook[], Cell[RawBoxes@ToBoxes["Python process ended",TraditionalForm],"Output"]]; ] Clear[pcmd] pcmd[cmd_String,process_:Unevaluated@$pythonprocess]:=Module[{status,err,out,p},
p = Evaluate[process];
status = ProcessStatus[p];
If[status=="Running",
WriteLine[p,cmd];
wlPythonpyerrcheck[];
];
out
]

Clear[pyerrcheck]
pyerrcheck[]:=Module[{err},
Pause@$pythonpause; err = ReadString[ProcessConnection[$pythonprocess,"StandardError"],EndOfBuffer];
If[\$pyfrontend,
NotebookWrite[MessagesNotebook[],
Print[err];
]

]

End[];

EndPackage[];
`
-

There's a "Python link" called Pythonika. I have used it briefly and it works.

What it does:

• translates basic data types, including arbitrary size integers, to/from Python
• makes it possible to implement functions in Python and call them from Mathematica

It does not provide any means to work with classes directly. Also, the implementation is rather hackish using unsafe practices (e.g. symbols are not localized to a context, and this has bitten me). To implement a link properly it would take lot more work.

I made a few basic fixes (e.g. using contexts), but I haven't used the thing in a long time. Contact me if you want the fixes.

-
Does nt compile and does nt work. – User12309 Aug 12 '14 at 20:01
Correct, it is deprecated and seems no longer maintained... – M.R. Jan 26 '15 at 2:36