0

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)
4
  • You run the script. It does some imports, defines the variable logfile and the function Main. But as far as I can see Main is never called.
    – Matthias
    Commented Mar 20, 2024 at 15:51
  • Yes. The script is given to me like this. This structure with the function "Main" can not be changed. I have to call the function "Main" and pass the argument "dataset" to it. The reason is, that the script is also called by ArcGIS Pro. This is why the question is called: "How to start a !function! in a python/propy script via c#?"
    – Gener4tor
    Commented Mar 20, 2024 at 16:01
  • 1
    Can you write a second Python script that imports this script and calls the function?
    – Matthias
    Commented Mar 20, 2024 at 21:38
  • I probably could. But this would not be my first solution. Ill prefer to call the function directly. Im sure this is possible.
    – Gener4tor
    Commented Mar 20, 2024 at 21:58

1 Answer 1

0

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);

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.