Running the ExcelToTable.py GP tool within a DropHandler add-in

1071
4
Jump to solution
04-19-2021 01:03 PM
StuartBricker
Emerging Contributor

I am attempting to run the ExcelToTable.py Geoprocessing script within a C# DropHandler class. The intent here is to allow the user to simply drop an Excel file containing attribute updates onto the map, and have the GP tool automatically handle the table import.

Going through the Geoprocessing samples, I see that since this GP tool is a python script, I cannot use the Geoprocessing.ExecuteToolAsync() method. Rather, I must use the Process.Start() method to run python scripts from within the ProSDK. Using the community samples snippet as a guide, I am able to get the ExcelToTable.py script to run, however I am unable to figure out how to pass the input file and output table parameters to the python script. In the community samples, there are no parameters being passed into the script, so I don't have an example to follow.

The code I have so far within the DropHandler class:

 

 

public override async void OnDrop(DropInfo dropInfo)
string InputFile = dropInfo.Items[0].Data.ToString();
string OutputTable = @"C:\Test\DropTest.gdb\Test1"; 
Debug.WriteLine($"File: {InputFile}");

// pro SDK snippet
var pathProExe = System.IO.Path.GetDirectoryName((new Uri(Assembly.GetEntryAssembly().CodeBase)).AbsolutePath)

if (pathProExe == null) return;
pathProExe = Uri.UnescapeDataString(pathProExe);
pathProExe = System.IO.Path.Combine(pathProExe, @"Python\envs\arcgispro-py3");
Debug.WriteLine(pathProExe);

var pathPython = @"C:\Program Files\ArcGIS\Pro\Resources\ArcToolBox\Scripts\ExcelToTable.py";

var myCommand = $@"/c """"{System.IO.Path.Combine(pathProExe, "python.exe")}"" ""{pathPython}""""";

Debug.WriteLine(myCommand);

var procStartInfo = new ProcessStartInfo("cmd", myCommand);

procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;

Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();

string result = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error)) result += string.Format("{0} Error: {1}", result, error);

System.Windows.MessageBox.Show(result);

 

 

The resulting Python error:

PyError.png

Which makes sense, since I never specified the Input file or output table. But at least this tells me that I am getting the script to start, albeit unsuccessfully.

 

 

procStartInfo.Arguments = "?"; // Do I pass the parameters here? If so, what is the syntax? 

 

 

So in other words, what is the correct syntax for running the ExcelToTable.py script, given the string parameters of InputFile, and OutputTable? Do I use the above property of procStartInfo?

Thanks for your assistance!

0 Kudos
1 Solution

Accepted Solutions
GKmieliauskas
Esri Regular Contributor

Hi,

This is a sample for ExcelToTable geoprocessing tool:

var parameters = Geoprocessing.MakeValueArray(InputFile, OutputTable, "", 1, "");
var environments = Geoprocessing.MakeEnvironmentArray(workspace: tempPath);
var gpResult = await Geoprocessing.ExecuteToolAsync("ExcelToTable_conversion", parameters,      environments, CancelableProgressor.None, GPExecuteToolFlags.None);

 

 

View solution in original post

4 Replies
DHuantes
Regular Contributor

I haven't tried the ExcelToTable but I have run a number of GP Tools using the Geoprocessing.ExecuteToolAsync() and I'm thinking most of them are actually in python.  Here is a method for running the RasterTIN_3d GP Tool

 

 

 

        public static async Task<IGPResult> CallRasterToTIN_GPTool(string l_newRaster)
        {
            string l_outputTIN = Project.Current.HomeFolderPath + @"\Terrain Data\TINs";

            
            // Make the sure the TINs subdirectory exists beneath Terrain Data
            if (System.IO.Directory.Exists(l_outputTIN) == false)
            {
                System.IO.Directory.CreateDirectory(l_outputTIN);
            }
            l_outputTIN += @"\Range_TIN";

            List<object> arguments = new List<object>
            {
                l_newRaster,    // Input Raster
                l_outputTIN,    // Output TIN
            };

            var l_returnValue = await Geoprocessing.ExecuteToolAsync("RasterTIN_3d", Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);
         

 

 

 

 

And here is another one for Creating a FeatureClass and optionally adding it to the map using the CreateFeatureclass_managment GP Tool.

 

 

 

        public static async Task<IGPResult> CreateFeatureClass(string featureclassName, string featureclassType, SpatialReference a_spatialReference, bool a_addToMap = true)
        {
            System.Diagnostics.Debug.WriteLine(CoreModule.CurrentProject.DefaultGeodatabasePath);
            List<object> arguments = new List<object>
            {
                CoreModule.CurrentProject.DefaultGeodatabasePath, // use the default geodatabase
                featureclassName,                                 // name of the feature class
                featureclassType,                                 // type of geometry
                "",                                               // no template
                "DISABLED",                                       // no m values
                "ENABLED",                                        // no z values
                a_spatialReference
            };

            if (a_addToMap)
            {
                IGPResult l_returnResult = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", Geoprocessing.MakeValueArray(arguments.ToArray()));
                if (l_returnResult.IsFailed == false)
                {
                    // Confirm FeatureClass added to map as Layer.  The only reason it would not is if user has turned
                    // on the feature that tells ArcGIS Pro not to add Geoprocessing results to the map
                    // This logic handles that condition
                    var l_layerReturned = MapView.Active.Map.FindLayers(featureclassName).FirstOrDefault() as FeatureLayer;
                    if (l_layerReturned == null)
                    {
                        Uri l_layerURI = new Uri(l_returnResult.ReturnValue);
                        await QueuedTask.Run(()=>  LayerFactory.Instance.CreateLayer(l_layerURI, MapView.Active.Map) );
                    }
                }
               
                return l_returnResult;
            }
            else
            {
                return await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", Geoprocessing.MakeValueArray(arguments.ToArray()),null,null,null,GPExecuteToolFlags.None);
            }

        }

 

 

 

 

You'll notice a pattern of passing a List<object> for each GP Tool.  That's the trick is knowing what should be in that list.  What I've generally done is make sure I can run the GP Tool via the ArcGIS Pro UI first.  When successful, I then click the "Details" Link at the bottom of the Geoprocessing Dockpane and review the Parameters list.  I then make sure when I implement it in code that the objects in my list align with Parameters list in the Details dialog as shown in attached screenshot.   Good luck!

Geoprocessing Tool Details Dialog with ParametersGeoprocessing Tool Details Dialog with Parameters

GKmieliauskas
Esri Regular Contributor

Hi,

This is a sample for ExcelToTable geoprocessing tool:

var parameters = Geoprocessing.MakeValueArray(InputFile, OutputTable, "", 1, "");
var environments = Geoprocessing.MakeEnvironmentArray(workspace: tempPath);
var gpResult = await Geoprocessing.ExecuteToolAsync("ExcelToTable_conversion", parameters,      environments, CancelableProgressor.None, GPExecuteToolFlags.None);

 

 

StuartBricker
Emerging Contributor

Awesome! Thank you both for your replies. Clearly I was mistaken in my belief that Python GP scripts cannot be run with ExecuteToolAsync(). So one final follow-up question: Where does one find the tool names in the docs for ExecuteToolAsync("Tool_Name", ...)? It is not immediately apparent what the first parameter should be by looking at the tool in Pro.

Once again, thank you both for helping to clarify that.

0 Kudos
GKmieliauskas
Esri Regular Contributor

HI,

Where does one find the tool names in the docs for ExecuteToolAsync("Tool_Name", ...)?

There is no place where you can find it. You can check my questions in Geo Net and you will find the same question and my workflow how I solve that task.

https://community.esri.com/t5/arcgis-pro-sdk-questions/when-will-net-developers-get-api-reference-fo... 

 

Please add comments to that thread and ask your colleagues to do the same. May be Esri will solve faster our problem.