Hi internet peoples! I'm hoping that someone could help me in testing an error that I've run into related to accessing a hosted feature layer via an update cursor.
I need to update one field based upon the value in another field, in a hosted feature layer. I used a Notebook in ArcGIS Pro (v2.9.5) to test a script that would accomplish what I need to do. I connect to my GIS(), access the item, obtain the URL of the layer (as there is only one), and pass it to a search cursor to perform the calculations needed for each row. This worked beautifully in a Notebook in Pro.
I want to set up the script to run nightly via a Task, so I copied my script to a Notebook in ArcGIS Online. I'm using the ArcGIS Notebook Python 3 Advanced - 7.0 Runtime. All parts of the script work, except when trying to access the URL in the search cursor. I can access the item, access the layer, and access the URL, but when I pass the URL to the search cursor, I get the error:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 with arcpy.da.UpdateCursor(roads_url, fields) as cursor:
2 for row in cursor:
3 newDate = row[0]
RuntimeError: cannot open 'https://services1.arcgis.com/###########/arcgis/rest/services/HFL_NAME/FeatureServer/0'
I tried adding a token to the URL to get an authenticated URL, but I received the same error. I also tried the Advanced 6.0 Runtime and received the same error. Further, I tried to create a FeatureSet and load the data into it via the URL, but received a similar error:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
Input In [77], in <cell line: 1>()
----> 1 roads_fset = arcpy.FeatureSet(roads_url)
2 roads_fset
File /opt/conda/lib/python3.9/site-packages/arcpy/arcobjects/mixins.py:1049, in FeatureSetMixin.__init__(self, *args, **kwargs)
1047 _BaseArcObject.__init__(self)
1048 if args or kwargs:
-> 1049 self._arc_object.load(*gp_fixargs(args), **gp_fixkwargs(kwargs))
RuntimeError: RecordSetObject: Cannot open table for Load
I have found no help documentation or forum questions related to this very specific issue. My code is below, if someone wants to try to recreate this error in an ArcGIS Online Notebook. Just switch out the UpdateCursor for a SearchCursor, while using your own hosted feature layer.
#search for the feature layer
portal_item = gis.content.get('abcdefghijklmnop')
#access the item's feature layers
roads_layer = portal_item.layers[0]
#return the url of the feature layer
roads_url = roads_layer.url
#field names for UpdateCursor calculations
fields = ['FieldOne','FieldTwo']
#UpdateCursor accessing the feature layer via its URL
with arcpy.da.UpdateCursor(roads_url, fields) as cursor:
for row in cursor:
#Do Something
del row, cursor
Thanks in advance to anyone who can test this script and/or determine if this is really a BUG!
Solved! Go to Solution.
Not sure what's wrong but I wouldn't use cursors for this for performance reasons.
In my experience ArcPy cursors are total dogs for working with hosted feature layers compared to using the FeatureLayer type in the ArcGIS API for Python. Use query() the features you want - only grabbing the field you need for calculation and the OIDs - then create a bunch of updates with just the OIDs and the derived field and push them through using edit_features().
Your mileage may vary but I've found this approach much better.
Also, secondary benefit, the query/edit_features approach doesn't require an advanced runtime.
Personal opinion: if you're working with hosted layers, you're better of using the ArcGIS Python API entirely instead of including ArcPy.
#search for the feature layer
portal_item = gis.content.get('abcdefghijklmnop')
#access the item's feature layers
roads_layer = portal_item.layers[0]
#field names for calculations
fields = ['objectid','FieldOne','FieldTwo']
# return a dataframe w/ features
df = roads_layer.query(out_fields=fields, as_df=True)
# calculate the field value in your dataframe
df['FieldTwo'] = # some calculation
# apply edited dataframe back to service as edits
roads_layer.edit_features(edits=df.spatial.to_featureset())
Not sure what's wrong but I wouldn't use cursors for this for performance reasons.
In my experience ArcPy cursors are total dogs for working with hosted feature layers compared to using the FeatureLayer type in the ArcGIS API for Python. Use query() the features you want - only grabbing the field you need for calculation and the OIDs - then create a bunch of updates with just the OIDs and the derived field and push them through using edit_features().
Your mileage may vary but I've found this approach much better.
Also, secondary benefit, the query/edit_features approach doesn't require an advanced runtime.
Personal opinion: if you're working with hosted layers, you're better of using the ArcGIS Python API entirely instead of including ArcPy.
#search for the feature layer
portal_item = gis.content.get('abcdefghijklmnop')
#access the item's feature layers
roads_layer = portal_item.layers[0]
#field names for calculations
fields = ['objectid','FieldOne','FieldTwo']
# return a dataframe w/ features
df = roads_layer.query(out_fields=fields, as_df=True)
# calculate the field value in your dataframe
df['FieldTwo'] = # some calculation
# apply edited dataframe back to service as edits
roads_layer.edit_features(edits=df.spatial.to_featureset())
Thank you both for the helpful suggestions as alternatives to accomplish the update of the field! I appreciate that they don't require the Advanced runtime, too. I accepted both of your replies as the solution as I took a bit from each suggestion for my working script. Thanks again!