it seems like a basic question, but even with the documentation and other posts I cannot get it to work properly. I've got a Python-Toolbox in which I establish the connection to a ArcSDE using a connection file. now I would like to list the content of the ArcSDE in my dockpane (because it looks prettier). I can list the content of my dockpane in my Python-Toolbox and display them. It seems that it's also correct how I pass them back (at least there is no error message). But I don't see how I can access the returned strings and arrays. How do I pass my ArcSDE content as string or array (or anything else) to my dockpane?
here is what I've got in my Python Toolbox:
import arcpy
from tkinter import messagebox
from osgeo import gdal
import os
import ast
class Toolbox(object):
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
self.label = "Toolbox"
self.alias = "toolbox"
# List of tool classes associated with this toolbox
self.tools = [ArcSDEContent]
def read_sde():
if os.path.exists(os.environ['AppDAta']+"/Esri/ArcGISPro/Favorites/xxx.sde"):
sde_connfile = os.environ['AppDAta']+"/Esri/ArcGISPro/Favorites/xxx.sde"
conn = arcpy.ArcSDESQLExecute(sde_connfile)
sql = "select t.name as mytype,i.name as myname, \
CASE \
WHEN has_table_privilege(user,i.name,'SELECT') THEN 1 \
ELSE 0 \
END AS mypriv \
FROM GDB_itemtypes t \
right join GDB_items i \
ON i.type = t.uuid \
where t.name in ( \
'Tin', \
'Geometric Network', \
'Survey Dataset', \
'Schematic Dataset', \
'Table', \
'Feature Class', \
'Raster Dataset', \
'Raster Catalog', \
'Network Dataset', \
'Terrain', \
'Parcel Fabric', \
'Mosaic Dataset', \
'Utility Network', \
'Parcel Dataset' \
);"
try:
sql_return = conn.execute(sql)
layer_files = []
layer_schemas = []
for i in sql_return:
if i[2] == 0:
continue
layer_type = i[0]
layer_fullname = sde_connfile + '/' + i[1]
layer_name = i[1].split('.')[1] + '.' + i[1].split('.')[2]
layer_shortname = i[1].split('.')[2]
layer_schema = i[1].split('.')[1]
if layer_schema not in layer_schemas:
layer_schemas.append(layer_schema)
layer_files.append([layer_name,layer_shortname,layer_schema,layer_fullname,layer_type])
layer_schemas.sort()
layer_files.sort()
return layer_files, layer_schemas
except Exception as err:
sql_return = False
else:
messagebox.showinfo(title="test 2", message="sde file does not exist")
class ArcSDEContent(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "ArcSDE Content"
self.description = ""
def getParameterInfo(self):
"""Define parameter definitions"""
params = []
params.append({
'name': 'layer_files',
'displayName': 'Layer Files',
'datatype': 'String',
'parameterType': 'Derived',
'direction': 'Output'
})
params.append({
'name': 'layer_schemas',
'displayName': 'Layer Schemas',
'datatype': 'String',
'parameterType': 'Derived',
'direction': 'Output'
})
return params
def isLicensed(self):
return True
def updateParameters(self, parameters):
return
def updateMessages(self, parameters):
return
def execute(self, parameters, messages):
layer_files, layer_schemas = read_sde()
# Set the output parameters with the results
parameters[0].value = ";".join(layer_files) # Join the list to a string
parameters[1].value = ";".join(layer_schemas)
and in my dockpane.xaml.cs I've got:
private async void ReadArcSDE(object sender, RoutedEventArgs e)
{
string installPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string toolboxPath = System.IO.Path.Combine(installPath, "MyPythonToolbox.pyt\\ArcSDEContent");
IGPResult result = await Geoprocessing.ExecuteToolAsync(toolboxPath, null, null, null, null, GPExecuteToolFlags.InheritGPOptions);
}
thanks for any hint
At the end of your dockpane.xaml.cs add
return result;
thanks @MatthewDriscoll for the hint. Apparantly I didn't phrase my problem correctly, because that's not what I meant. I mean how can I now access the content of the result? I mean how can I extract layer_files layer_schemas? (for example the layer_name that is on the second position in each layer_file?) every method I try returns nonsens or void. my best try was with
IEnumerable<Tuple<string, string, string, bool>> parameters = result.Parameters;
but I just cant figure out how to access my result values.
Hi,
IGPResult has property Values.
It contains output values or null if tool execution fails. It's list of strings
I'm sorry, but I'm still stuck... I tried to make my example as easy as possible, but I don't get it to work at all...
in my python toolbox:
class ArcSDEContent(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "ArcSDE Content"
self.description = ""
def getParameterInfo(self):
"""Define parameter definitions"""
params = []
params.append({
'name': 'layer_files',
'displayName': 'Layer Files',
'datatype': ['String'],
'parameterType': 'Derived',
'direction': 'Output'
})
return params
def isLicensed(self):
return True
def updateParameters(self, parameters):
return
def updateMessages(self, parameters):
return
def execute(self, parameters, messages):
#read_sde()
#return
try:
# parameters.append("test1")
arcpy.SetParameterAsText(0, "Your output value")
return
except Exception as e:
arcpy.AddError(f"An error occurred: {str(e)}")
and in my Doxpane.xaml.cs
private async void ReadArcSDE(object sender, RoutedEventArgs e)
{
string installPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string toolboxPath = System.IO.Path.Combine(installPath, "test.pyt\\ArcSDEContent");
IGPResult result = await Geoprocessing.ExecuteToolAsync(toolboxPath, null, null, null, null, GPExecuteToolFlags.InheritGPOptions);
string value = result.ReturnValue;
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(value, "return value");
/* var outputParameterValue = result.Parameters;
foreach (Tuple<string, string, string, bool> param in outputParameterValue)
{
string i1 = param.Item1;
string i2 = param.Item2;
string i3 = param.Item3;
bool i4 = param.Item4;
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("parameters", "item 1:" + i1);
}*/
values = result.Values;
foreach (string val in values)
{
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(val ,"values val");
}
}
how can I access my value from my python script? it shouldn't be that hard...
@GKmieliauskas is correct you need to use the IGPResult. Below is how I access python results in the cs.
public async Task<IGPResult> ExecuteModel()
{
var progDlg = new ProgressDialog("Running Geoprocessing Tool", "Cancel");
progDlg.Show();
var progsrc=new CancelableProgressorSource(progDlg);
var pathPython = System.IO.Path.GetDirectoryName((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
pathPython = Uri.UnescapeDataString(pathPython);
System.Diagnostics.Debug.WriteLine(pathPython);
var tool_path = System.IO.Path.Combine(pathPython, @"YourPythonScript.pyt\Tool");
var parameters = Geoprocessing.MakeValueArray();
IGPResult gp_result = await Geoprocessing.ExecuteToolAsync(tool_path, parameters, null, new CancelableProgressorSource(progDlg).Progressor);
return gp_result;
}
thanks @MatthewDriscoll for your reply. I don't see why I would need to return the gp_result from my method. I need the result in the same method later on - imagine you do sth with gp_result in "ExecuteModel". how would you access the results? As far as I understand it are you returning the gp_result to the "scope" where you call ExecuteModel.
I think the issue is in line 34:
arcpy.SetParameterAsText(0, "Your output value")
First parameters of SetParameterAsText can't be 0. As I understand your tool has 5 parameters, last parameter is your output. So, first parameter must be 4.
I am not sure, but I use SetParameter instead of SetParameterAsText.
thanks @GKmieliauskas, how do you access that parameter?
As I wrote earlier.
var gpResult = Geoprocessing.ExecuteToolAsync(fullToolPath, parameters, null, null, (eventName, o) => GPHelper.ProcessGPEvent(eventName, o), GPExecuteToolFlags.AddToHistory);
gpResult.Wait();
string errMsg = string.Empty;
if (gpResult.Result.IsFailed)
{
throw new Exception("Tool failed");
}
else
{
var resultValues = gpResult.Result.Values;
if (resultValues == null)
{
throw new Exception("Nothing is returned");
}
else
{
if (resultValues.Count > 0)
{
// reading output parameters
}
}
}