2

I am trying to run a python script from a c# console application. This c# code works fine until I import our custom python module that in turn imports other modules, e.g. arcpy, keyring, etc within the python script. The script runs fine from the cmd line but once in c# it just hangs. In the end, a system deadlock error pops up. How do I get my python to run? The goal is to get the password from python to c#. I am open to other approaches...

c#

        private static string getPassword(string database)
        {
            ProcessStartInfo start = new ProcessStartInfo();
            start.FileName = @"C:\Python27\ArcGIS10.6\python.exe";
            string script = @"C:\src\xxxx\etw_password.py";
            start.Arguments = $"\"{script}\" \"{database}\"";
            start.UseShellExecute = false;
            start.CreateNoWindow = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            string errors;
            string password;
            Console.WriteLine(start.Arguments);
            using(Process process = Process.Start(start))
            {
                errors = process.StandardError.ReadToEnd();
                password = process.StandardOutput.ReadToEnd();
            }


            return password;
        }

python: not working-- I replaced our custom python security calls with "x"

import sys
import xxxx

database = sys.argv[1]
password = xxxx.xxxx(database, 'xxxx')
print password

python: this works fine

import sys

database = sys.argv[1]
print database

I also run the test below to check if it was just our module or if the problem extended to others. I tested with numpy and arcpy. Both failed.

python: not working

import sys
import numpy

database = sys.argv[1]
print database
fallingdog
  • 192
  • 1
  • 2
  • 17

2 Answers2

0

The issue lies with your script, not C#. Your C# code is well-formed and working (I tested it out by replacing your script with a hello world script that takes in one argument, and it printed the output correctly).

If you're saying it works on the command line, then it might be important to note what path you are running the script from. Your script might contain relative path dependencies. This would, in turn, affect the C# code because you may need to start in that directory first.

If you want my test, here it is:

script.py:

import sys

database = sys.argv[1]
print("Hello, " + database)

Program.cs:

        static void Main(string[] args)
        {
            var pwd = getPassword("World!");
            Console.WriteLine($"OUTPUT: {pwd}");
        }

        private static string getPassword(string database)
        {
            ProcessStartInfo start = new ProcessStartInfo();
            start.FileName = @"C:\Users\<path-to-my>\python.exe";
            string script = @"C:\<path-to-my>\script.py";
            start.Arguments = $"\"{script}\" \"{database}\"";
            start.UseShellExecute = false;
            start.CreateNoWindow = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            string errors;
            string password;
            Console.WriteLine(start.Arguments);
            using (Process process = Process.Start(start))
            {
                errors = process.StandardError.ReadToEnd();
                password = process.StandardOutput.ReadToEnd();
            }

            return password;
        }

Output:

enter image description here

Tam Bui
  • 2,940
  • 2
  • 18
  • 27
  • I ran almost the exact same test python script from within the c#. And it works fine. The problem appears when I try to use a python model that is not part of the "out of the box" python install. – fallingdog May 28 '20 at 21:55
  • The command line is not just a terminal window where python freely runs. There are environment variables that get set prior to the command line window opening. Your C# script is probably missing one of those python dependencies, I suspect. – Tam Bui May 28 '20 at 22:00
  • so, I need something like my windows system environment python home set in the process info? – fallingdog May 28 '20 at 22:09
  • I don't suspect that one to be the issue. So did you eliminate the path where you're running from to be the issue? Meaning, your script will run from any path in the command line? – Tam Bui May 28 '20 at 22:37
  • I can run if from any path (if I understand your question) e.g. D:\Users\xxx>"C:\src\xxxx\xxxx.py" "xxxx" – fallingdog May 28 '20 at 23:23
  • Yes, that was my question and thanks for checking. Another alternative approach would be to change your Process to run the shell "cmd" as your process, and the arguments as "python C:\src\xxxx\etw_password.py {script} {database}". Example here: https://stackoverflow.com/questions/1469764/run-command-prompt-commands – Tam Bui May 28 '20 at 23:47
  • Thanks Tam. When I started having problems I looked at using the shell -- clearly c# is missing parts of the python install. But it looks like process.StandardOutput.ReadToEnd() is not possible if you do this. As passing the password is the point I saw it as a dead end. – fallingdog May 29 '20 at 17:04
  • 1
    Thanks for the help on this one. I appreciate all the feedback. I gave up and wrapped the c# exe in python. – fallingdog Jun 02 '20 at 16:54
0

I had the same problem, plus I was using a virtual python environment that I had created before installing my dependencies. So if you are not working with a virtual environment, you will only have to set the environment variable PYTHONPATH to the directory where your custom modules are installed. Btw. I am using Python 3.7.9. on Windows.

In my case I had created a virtual environment using

python -m venv .meinvenv

I figured that I would need to set the same environment variables in my ProcessStartInfo that would be set when I called the activate script for my virtual environment from the command line. So I set the environment variable for my virtual environment (using the variable start from your code snippet):

start.EnvironmentVariables["VIRTUAL_ENV"] = "C:\\Users\\mattgl\\.meinvenv";

And I added to the environment variables a modified path, which consisted of the Scripts folder of my virtual environment prepended to the original path:

start.EnvironmentVariables["PATH"] = "C:\\Users\\mattgl\\.meinvenv\\Scripts;" + start.EnvironmentVariables["PATH"];

After that, although my script was executed, I got a ModuleNotFoundError: No module named 'spacy' (because spacy happened to be the first special module to be imported in my script).

That I solved by specifying the environment variable PYTHONPATH in my ProcessStartInfo object like so:

start.EnvironmentVariables["PYTHONPATH"] = "C:\\Users\\mattgl\\.meinvenv\\Lib\\site-packages";

The path I specified was the path in my virtual Python environment where all modules had been installed before. Yours will be different.

After that, my python script could resolve all its dependencies and ran just fine.

mattgl
  • 30
  • 1
  • 7