My python script (c:\Temp\StartPython\test.py) looks like this:
import arcpy
import string, sys, os
import ctypes
logfile ="C:\\Temp\\StartPython\\Logfile.log"
def Main(dataset):
print ("Started with argument " + dataset)
datei = open(logfile,'a')
datei.write("Started with argument " + dataset)
I want to start the function "main" from the script via C#. For this I have to use the propy.bat which is used by ArcGis Pro to establish a CONDA-Enviroment for phython.
@echo off
@CALL :normalizepath scripts_path "%~dp0"
:: get the active environment from PythonEnvUtils.exe
FOR /F "delims=" %%i IN ('"%scripts_path%..\..\PythonEnvUtils.exe"') DO set CONDA_NEW_ENV=%%i
@set CONDA_SKIPCHECK=1
@set "CONDA_PREFIX=%CONDA_NEW_ENV%"
@set "CONDA_BACKUP_PATH=%PATH%"
@SET "activate_path="%scripts_path%activate.bat" "%CONDA_NEW_ENV%"
@set "deactivate_path="%scripts_path%deactivate.bat""
@call %activate_path%
python.exe %*
@set PY_ERRORLEVEL=%ERRORLEVEL%
@call %deactivate_path%
@set "PATH=%CONDA_BACKUP_PATH%"
@set "CONDA_BACKUP_PATH="
@exit /b %PY_ERRORLEVEL%
:normalizepath
@set "%1=%~dpfn2"
@exit /b
I was able to create a class for starting the script, which looks like this:
internal class RunProcess
{
private Process _process;
private StringBuilder _sbOut = new StringBuilder();
private StringBuilder _sbError = new StringBuilder();
public (string Output, string Error, int ErrCode) RunProcessGrabOutput(string Executable, string Arguments, string WorkingDirectory)
{
int exitCode = -1;
try
{
_sbOut.Clear();
_sbError.Clear();
_process = new Process();
_process.StartInfo.FileName = Executable;
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.WorkingDirectory = WorkingDirectory;
_process.StartInfo.RedirectStandardInput = true;
_process.StartInfo.RedirectStandardOutput = true;
_process.StartInfo.RedirectStandardError = true;
_process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
_process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
_process.StartInfo.CreateNoWindow = true;
_process.StartInfo.EnvironmentVariables.Add("PYTHONUNBUFFERED", "TRUE");
if (!string.IsNullOrEmpty(Arguments))
_process.StartInfo.Arguments = Arguments;
_process.EnableRaisingEvents = true;
_process.OutputDataReceived += new DataReceivedEventHandler(ProcessOutputHandler);
_process.ErrorDataReceived += new DataReceivedEventHandler(ProcessErrorHandler);
_process.Start();
_process.BeginOutputReadLine();
_process.BeginErrorReadLine();
// You can set the priority only AFTER the you started the process.
_process.PriorityClass = ProcessPriorityClass.BelowNormal;
_process.WaitForExit();
exitCode = _process.ExitCode;
}
catch
{
// This is how we indicate that something went wrong.
throw;
}
return (_sbOut.ToString(), _sbError.ToString(), exitCode);
}
private void ProcessOutputHandler(object SendingProcess, DataReceivedEventArgs OutLine)
{
_sbOut.AppendLine(OutLine.Data);
}
private void ProcessErrorHandler(object SendingProcess, DataReceivedEventArgs OutLine)
{
_sbError.AppendLine(OutLine.Data);
}
}
This is how I try to start the script:
var executable = "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\Scripts\\propy.bat";
var workingDir = "C:\\Program Files\\ArcGIS\\Pro\\bin";
var myArguments = "\"C:\\Temp\\StartPython\\test.py\" \"C:\\somePath\" ";
var process = new RunProcess();
var processOutcome = process.RunProcessGrabOutput(executable,
myArguments, workingDir);
RunProcessGrabOutput will last ~ 1 second and afterwards no Logfile is written and the processOutcome is kinda empty:
processOutcome ("\r\n", "\r\n", 0) (string Output, string Error, int ErrCode)
After some searching I found an answer here Run function from the command line
So this is how I call the function:
var executable = "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\Scripts\\propy.bat";
var workingDir = "C:\\Daten\\RadSvn\\Prototypes\\StartPythonScript\\StartPythonScript\\Scripts";
var myArguments = "-c \"from Test import Main;Main('Hallo')\"";
var process = new RunProcess();
var processOutcome = process.RunProcessGrabOutput(executable,
myArguments, workingDir);