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
thank you @GKmieliauskas
I tried to adapt my code to your sample. my python:
def execute(self, parameters, messages):
try:
string_to_pass = "Your output value"
arcpy.SetParameter(4, string_to_pass)
return
except Exception as e:
arcpy.AddError(f"An error occurred: {str(e)}")
and then in my 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, "xxxx.pyt\\ArcSDEContent");
IGPResult result = await Geoprocessing.ExecuteToolAsync(toolboxPath, null, null, null, null, GPExecuteToolFlags.InheritGPOptions);
var resultValues = result.Values;
foreach (string val in resultValues)
{
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(val, "values val");
}
}
it seems to work until line 7 "var resultValues" - at least until there I don't get an error message (unless I try result.Result.Values). But as soon as I try to access / print my result values (see line 9 to 12), I get "System.NullReferenceException: 'Object reference not set to an instance of an object'". where is my mistake?
You need to check 'result' as in my last comment. Your geoprocessing tool could fail or etc. I don't have possibility to check, but it seems for your geoprocessing calling code could be like this:
var gpResult = await Geoprocessing.ExecuteToolAsync(fullToolPath, parameters, null, null, (eventName, o) => GPHelper.ProcessGPEvent(eventName, o), GPExecuteToolFlags.AddToHistory);
string errMsg = string.Empty;
if (gpResult.IsFailed)
{
throw new Exception("Tool failed");
}
else
{
var resultValues = gpResult.Values;
if (resultValues == null)
{
throw new Exception("Nothing is returned");
}
else
{
if (resultValues.Count > 0)
{
// reading output parameters
}
}
}