197

This sort of question has been asked before in varying degrees, but I feel it has not been answered in a concise way and so I ask it again.

I want to run a script in Python. Let's say it's this:

if __name__ == '__main__':
    with open(sys.argv[1], 'r') as f:
        s = f.read()
    print s

Which gets a file location, reads it, then prints its contents. Not so complicated.

Okay, so how do I run this in C#?

This is what I have now:

    private void run_cmd(string cmd, string args)
    {
        ProcessStartInfo start = new ProcessStartInfo();
        start.FileName = cmd;
        start.Arguments = args;
        start.UseShellExecute = false;
        start.RedirectStandardOutput = true;
        using (Process process = Process.Start(start))
        {
            using (StreamReader reader = process.StandardOutput)
            {
                string result = reader.ReadToEnd();
                Console.Write(result);
            }
        }
    }

When I pass the code.py location as cmd and the filename location as args it doesn't work. I was told I should pass python.exe as the cmd, and then code.py filename as the args.

I have been looking for a while now and can only find people suggesting to use IronPython or such. But there must be a way to call a Python script from C#.

Some clarification:

I need to run it from C#, I need to capture the output, and I can't use IronPython or anything else. Whatever hack you have will be fine.

P.S.: The actual Python code I'm running is much more complex than this, and it returns output which I need in C#, and the C# code will be constantly calling the Python code.

Pretend this is my code:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
John Smith
  • 7,243
  • 6
  • 49
  • 61
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131

9 Answers9

170

The reason it isn't working is because you have UseShellExecute = false.

If you don't use the shell, you will have to supply the complete path to the python executable as FileName, and build the Arguments string to supply both your script and the file you want to read.

Also note, that you can't RedirectStandardOutput unless UseShellExecute = false.

I'm not quite sure how the argument string should be formatted for python, but you will need something like this:

private void run_cmd(string cmd, string args)
{
     ProcessStartInfo start = new ProcessStartInfo();
     start.FileName = "my/full/path/to/python.exe";
     start.Arguments = string.Format("{0} {1}", cmd, args);
     start.UseShellExecute = false;
     start.RedirectStandardOutput = true;
     using(Process process = Process.Start(start))
     {
         using(StreamReader reader = process.StandardOutput)
         {
             string result = reader.ReadToEnd();
             Console.Write(result);
         }
     }
}
uldall
  • 2,458
  • 1
  • 17
  • 31
Master Morality
  • 5,837
  • 6
  • 31
  • 43
  • 1
    i want to be able to take the output to my program to be used later. so i need to have shellexecute as false. you are saying if i pass `c:\python26\python.exe` as `cmd` and then `c:\temp\code.py c:\temp\testfile.txt` as `args` it should work? – Inbar Rose Aug 02 '12 at 14:12
  • I updated with a quick example, I ran into the same issue when I did something similar with node – Master Morality Aug 02 '12 at 14:14
  • okay, it works for me now. the problem is that you need to format the strings very carefully. any paths need `"PATH"` even if there are no spaces... strange... – Inbar Rose Aug 02 '12 at 15:01
  • Mine works without providing the full path. I am setting `UseShellExecute` to `false` and `RedirectStandardOutput` to `true`. – Nikhil Girraj Jun 24 '15 at 04:57
  • 2
    Works without providing the path if the Python installer was told to add the Python directory to the environment variable PATH (system or user specific). – Manfred Mar 28 '17 at 20:08
  • why my console go away immediately? I have tried to use process.WaitForExit() but it also goes immediately. I cannot capture any output from my python script. – user6539552 Jun 30 '18 at 16:01
  • Add a line of `Console.ReadLine();` after `Console.Write(result);` and you should be able to see the result because it is waiting for any key press to exit. – Leon Chang Sep 29 '19 at 20:10
  • FYI I could not get the output because my file name has special characters, be careful! – Roshna Omer May 27 '20 at 20:35
  • 5
    @MasterMorality , the python scripts executes fine , but if there is some module dependency in the python, how can we resolve that? – Harmandeep Singh Kalsi Sep 04 '20 at 15:21
  • 1
    @HarmandeepSinghKalsi Because you are providing the path of the Python .exe file, you have control over which Python executable to run. You can use Pip to install the dependencies for that python environment in a separate command line terminal. – Fritz W Oct 25 '22 at 05:58
72

If you're willing to use IronPython, you can execute scripts directly in C#:

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

private static void doPython()
{
    ScriptEngine engine = Python.CreateEngine();
    engine.ExecuteFile(@"test.py");
}

Get IronPython here.

Chris Dunaway
  • 10,974
  • 4
  • 36
  • 48
  • 7
    explain this to me, can i do this without having to download anything? c# comes ready with this plugin? also - can i run external scripts with this? – Inbar Rose Aug 02 '12 at 14:57
  • You would have to install IronPython, which is open source. I have updated the answer. – Chris Dunaway Aug 02 '12 at 15:04
  • 12
    note that IronPython and Python are not exactly the same thing. Just for the record... – Ron Klein Apr 22 '13 at 09:15
  • 1. Is IronPython compatible with .NET 3.5? 2. Can I pass any parameters while executing python file (those parameters may be instances of my own classes)? The most useful thing would be if I could run just one function from python script with known name and arguments. – Sushi271 Oct 11 '16 at 12:02
  • 5
    IronPython doesn't seem to support the same set of language features as Python 3.6.x does. Therefore IronPython is only an option if you don't use any of those language features. It's definitely worth a try, though. – Manfred Mar 28 '17 at 20:05
  • 2
    can we run python 3.6 with ironpython 2.7 version. I tried but its not import any python libraries. I am getting `unexpected token from` please help – Pyd Jan 29 '18 at 06:56
  • 1
    No, IronPython is only compatible with Python 2.7. IronPython3 is in the works. – Dimitar Aug 29 '19 at 15:44
  • 1
    @RonKlein, they are not the same, and if you are trying to use a library such as scikit-learn (for ML purposes), it won't work for you either – moarra Jan 28 '20 at 10:50
38

Execute Python script from C

Create a C# project and write the following code.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            run_cmd();
        }

        private void run_cmd()
        {

            string fileName = @"C:\sample_script.py";

            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(@"C:\Python27\python.exe", fileName)
            {
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            p.Start();

            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();

            Console.WriteLine(output);

            Console.ReadLine();

        }
    }
}

Python sample_script

print "Python C# Test"

You will see the 'Python C# Test' in the console of C#.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rohit Salunke
  • 1,073
  • 1
  • 10
  • 14
  • 1
    I have a python script file in a Windows folder like `C:\Users\Documents\Visual Studio 2019`. Because of the space in the folder path, it is treated as args' delimiter, so I got the `fileName` cannot be found. Is there a way to escape the space? – Leon Chang Sep 29 '19 at 20:27
  • I have a script that leverages pip packages. Will this still work? Do I just put the packages in the same folder as the python.exe? – N-ate Feb 27 '21 at 18:03
  • Maybe pip packages will be in venv\Lib\site-packages where the .py script is, worth a try – Epirocks May 14 '23 at 23:05
20

I ran into the same problem and Master Morality's answer didn't do it for me. The following, which is based on the previous answer, worked:

private void run_cmd(string cmd, string args)
{
 ProcessStartInfo start = new ProcessStartInfo();
 start.FileName = cmd;//cmd is full path to python.exe
 start.Arguments = args;//args is path to .py file and any cmd line args
 start.UseShellExecute = false;
 start.RedirectStandardOutput = true;
 using(Process process = Process.Start(start))
 {
     using(StreamReader reader = process.StandardOutput)
     {
         string result = reader.ReadToEnd();
         Console.Write(result);
     }
 }
}

As an example, cmd would be @C:/Python26/python.exe and args would be C://Python26//test.py 100 if you wanted to execute test.py with cmd line argument 100. Note that the path the .py file does not have the @ symbol.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Derek
  • 373
  • 3
  • 12
5

Actually its pretty easy to make integration between Csharp (VS) and Python with IronPython. It's not that much complex... As Chris Dunaway already said in answer section I started to build this inegration for my own project. N its pretty simple. Just follow these steps N you will get your results.

step 1 : Open VS and create new empty ConsoleApp project.

step 2 : Go to tools --> NuGet Package Manager --> Package Manager Console.

step 3 : After this open this link in your browser and copy the NuGet Command. Link: https://www.nuget.org/packages/IronPython/2.7.9

step 4 : After opening the above link copy the PM>Install-Package IronPython -Version 2.7.9 command and paste it in NuGet Console in VS. It will install the supportive packages.

step 5 : This is my code that I have used to run a .py file stored in my Python.exe directory.

using IronPython.Hosting;//for DLHE
using Microsoft.Scripting.Hosting;//provides scripting abilities comparable to batch files
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
class Hi
{
private static void Main(string []args)
{
Process process = new Process(); //to make a process call
ScriptEngine engine = Python.CreateEngine(); //For Engine to initiate the script
engine.ExecuteFile(@"C:\Users\daulmalik\AppData\Local\Programs\Python\Python37\p1.py");//Path of my .py file that I would like to see running in console after running my .cs file from VS.//process.StandardInput.Flush();
process.StandardInput.Close();//to close
process.WaitForExit();//to hold the process i.e. cmd screen as output
}
} 

step 6 : save and execute the code

Daulmalik
  • 59
  • 1
  • 2
  • 3
    As a developer I don't pick a solution because it's "easy" to implement. I pick one that does the job. IronPython is ported only to python 2.7 and work on python 3 is on course for a couple of years now, without end in sight. Hope your python code is in the right version. – peter.cyc Feb 12 '20 at 17:04
  • 1
    as of 27 april 2020: https://github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10, but still not python 3. – Luuk Jun 20 '20 at 15:06
3

Set WorkingDirectory or specify the full path of the python script in the Argument

ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "C:\\Python27\\python.exe";
//start.WorkingDirectory = @"D:\script";
start.Arguments = string.Format("D:\\script\\test.py -a {0} -b {1} ", "some param", "some other param");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
    using (StreamReader reader = process.StandardOutput)
    {
        string result = reader.ReadToEnd();
        Console.Write(result);
    }
}
LIU YUE
  • 1,593
  • 11
  • 19
1

I had the same issue and used answers on here to solve it using a process. I had conflicts between my .NET and IronPython so wasn't successful there. This works well with my python 3.10.

    public void Run_cmd2(string exe, string args, string output )
    {
        var outputStream = new StreamWriter(output);
        // create a process with the name provided by the 'exe' variable 
        Process cmd = new Process();
        cmd.StartInfo.FileName = exe;
        //define you preference on the window and input/output 
        cmd.StartInfo.RedirectStandardInput = true;
        cmd.StartInfo.RedirectStandardOutput = true;
        cmd.StartInfo.CreateNoWindow = true;
        cmd.StartInfo.UseShellExecute = false;
        // write the output to file created 
        cmd.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
        {
            if (!String.IsNullOrEmpty(e.Data))
            {
                outputStream.WriteLine(e.Data);
            }
        });
        cmd.Start();
        // write to the console you opened. In this case for example the python console 
        cmd.StandardInput.WriteLine(args);
        //Read the output and close everything. make sure you wait till the end of the process 
        cmd.BeginOutputReadLine();
        cmd.StandardInput.Flush();
        cmd.StandardInput.Close();
        cmd.WaitForExit();
        //close the process. writing to debug helps when coding
        outputStream.Close();
        //Console.WriteLine(cmd.StandardOutput.ReadToEnd()); 
        cmd.Close();
        Debug.WriteLine("\n\n Process done!");
        //Console.ReadLine();
    }

Example call:

string pythonEngine = "C:\ProgramData\Anaconda3\envs\compVision\python.exe";

string pythonArguements = "import os ; os.chdir('C:\YourPath\excelWorkbooks') ; import testSearch ; testSearch.performAdd(2, 3)";

// here a function in testSearch.py is called. To run the .py directly do this:

string pythonArguements = "import os ; os.chdir('C:\YourPath\excelWorkbooks') ; import testSearch ; testSearch.py";

outFile = "C:\YourPath\output.txt";

_yourModuleName.Run_cmd2(pythonEngine, pythonArguements, outFile);

antcrew
  • 21
  • 3
0

I am having problems with stdin/stout - when payload size exceeds several kilobytes it hangs. I need to call Python functions not only with some short arguments, but with a custom payload that could be big.

A while ago, I wrote a virtual actor library that allows to distribute task on different machines via Redis. To call Python code, I added functionality to listen for messages from Python, process them and return results back to .NET. Here is a brief description of how it works.

It works on a single machine as well, but requires a Redis instance. Redis adds some reliability guarantees - payload is stored until a worked acknowledges completion. If a worked dies, the payload is returned to a job queue and then is reprocessed by another worker.

V.B.
  • 6,236
  • 1
  • 33
  • 56
  • Why wouldn't you just use in-out files? instead of having the pipes handle all of that work. – Inbar Rose Dec 27 '16 at 08:22
  • @InbarRose I already had the system for .NET, so adding Python processing was very easy and I still have distribution and reliability - e.g. I could post payload from a Windows machine and process it from a Linux machine - files wouldn't work in this case. – V.B. Dec 27 '16 at 08:48
  • @InbarRose And when payload is really big, I could pass a filename on the same machine or S3 reference on AWS, etc... – V.B. Dec 27 '16 at 08:49
0

had same issure and this worked for me:

using IronPython.Hosting;

  var engine = Python.CreateEngine();

  engine.ExecuteFile("") //put the directory of the program in the quote marks