This repository has been archived by the owner on Mar 31, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 155
/
featureservicetools.py
756 lines (685 loc) · 33 KB
/
featureservicetools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
from __future__ import print_function
from __future__ import absolute_import
from .securityhandlerhelper import securityhandlerhelper
dateTimeFormat = '%Y-%m-%d %H:%M'
import arcrest
from arcrest.agol import FeatureLayer
from arcrest.agol import FeatureService
from arcrest.ags import FeatureService
from arcrest.hostedservice import AdminFeatureService
from arcrest.common.spatial import scratchFolder, scratchGDB, json_to_featureclass
from arcrest.common.general import FeatureSet
from arcresthelper.common import chunklist
import datetime, time
import json
import os
from . import common
import gc
try:
import arcpy
arcpyFound = True
except:
arcpyFound = False
import traceback, inspect, sys
import collections
#----------------------------------------------------------------------
def trace():
"""Determines information about where an error was thrown.
Returns:
tuple: line number, filename, error message
Examples:
>>> try:
... 1/0
... except:
... print("Error on '{}'\\nin file '{}'\\nwith error '{}'".format(*trace()))
...
Error on 'line 1234'
in file 'C:\\foo\\baz.py'
with error 'ZeroDivisionError: integer division or modulo by zero'
"""
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
filename = inspect.getfile(inspect.currentframe())
# script name + line number
line = tbinfo.split(", ")[1]
# Get Python syntax error
#
synerror = traceback.format_exc().splitlines()[-1]
return line, filename, synerror
class featureservicetools(securityhandlerhelper):
#----------------------------------------------------------------------
def RemoveAndAddFeatures(self, url, pathToFeatureClass, id_field, chunksize=1000):
"""Deletes all features in a feature service and uploads features from a feature class on disk.
Args:
url (str): The URL of the feature service.
pathToFeatureClass (str): The path of the feature class on disk.
id_field (str): The name of the field in the feature class to use for chunking.
chunksize (int): The maximum amount of features to upload at a time. Defaults to 1000.
Raises:
ArcRestHelperError: if ``arcpy`` can't be found.
"""
fl = None
try:
if arcpyFound == False:
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror": "ArcPy required for this function"
})
arcpy.env.overwriteOutput = True
tempaddlayer= 'ewtdwedfew'
if not arcpy.Exists(pathToFeatureClass):
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror": "%s does not exist" % pathToFeatureClass
}
)
fields = arcpy.ListFields(pathToFeatureClass,wild_card=id_field)
if len(fields) == 0:
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror": "%s field does not exist" % id_field
})
strFld = True
if fields[0].type != 'String':
strFld = False
fl = FeatureLayer(
url=url,
securityHandler=self._securityHandler)
id_field_local = arcpy.AddFieldDelimiters(pathToFeatureClass, id_field)
idlist = []
print( arcpy.GetCount_management(in_rows=pathToFeatureClass).getOutput(0) + " features in the layer")
with arcpy.da.SearchCursor(pathToFeatureClass, (id_field)) as cursor:
allidlist = []
for row in cursor:
if (strFld):
idlist.append("'" + row[0] +"'")
else:
idlist.append(row[0])
if len(idlist) >= chunksize:
allidlist.append(idlist)
idlist = []
if len(idlist) > 0:
allidlist.append(idlist)
for idlist in allidlist:
idstring = ' in (' + ','.join(map(str,idlist)) + ')'
sql = id_field + idstring
sqlLocalFC = id_field_local + idstring
results = fl.deleteFeatures(where=sql,
rollbackOnFailure=True)
if 'error' in results:
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror":results['error']
})
elif 'deleteResults' in results:
print ("%s features deleted" % len(results['deleteResults']))
for itm in results['deleteResults']:
if itm['success'] != True:
print (itm)
else:
print (results)
arcpy.MakeFeatureLayer_management(pathToFeatureClass,tempaddlayer,sqlLocalFC)
results = fl.addFeatures(fc=tempaddlayer)
if 'error' in results:
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror":results['error']
})
elif 'addResults' in results:
print ("%s features added" % len(results['addResults']))
for itm in results['addResults']:
if itm['success'] != True:
print (itm)
else:
print (results)
idlist = []
if 'error' in results:
raise common.ArcRestHelperError({
"function": "RemoveAndAddFeatures",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror":results['error']
})
else:
print (results)
except arcpy.ExecuteError:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "create_report_layers_using_config",
"line": line,
"filename": filename,
"synerror": synerror,
"arcpyError": arcpy.GetMessages(2),
}
)
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "AddFeaturesToFeatureLayer",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
gc.collect()
#----------------------------------------------------------------------
def EnableEditingOnService(self, url, definition = None):
"""Enables editing capabilities on a feature service.
Args:
url (str): The URL of the feature service.
definition (dict): A dictionary containing valid definition values. Defaults to ``None``.
Returns:
dict: The existing feature service definition capabilities.
When ``definition`` is not provided (``None``), the following values are used by default:
+------------------------------+------------------------------------------+
| Key | Value |
+------------------------------+------------------------------------------+
| hasStaticData | ``False`` |
+------------------------------+------------------------------------------+
| allowGeometryUpdates | ``True`` |
+------------------------------+------------------------------------------+
| enableEditorTracking | ``False`` |
+------------------------------+------------------------------------------+
| enableOwnershipAccessControl | ``False`` |
+------------------------------+------------------------------------------+
| allowOthersToUpdate | ``True`` |
+------------------------------+------------------------------------------+
| allowOthersToDelete | ``True`` |
+------------------------------+------------------------------------------+
| capabilities | ``"Query,Editing,Create,Update,Delete"`` |
+------------------------------+------------------------------------------+
"""
adminFS = AdminFeatureService(url=url, securityHandler=self._securityHandler)
if definition is None:
definition = collections.OrderedDict()
definition['hasStaticData'] = False
definition['allowGeometryUpdates'] = True
definition['editorTrackingInfo'] = {}
definition['editorTrackingInfo']['enableEditorTracking'] = False
definition['editorTrackingInfo']['enableOwnershipAccessControl'] = False
definition['editorTrackingInfo']['allowOthersToUpdate'] = True
definition['editorTrackingInfo']['allowOthersToDelete'] = True
definition['capabilities'] = "Query,Editing,Create,Update,Delete"
existingDef = {}
existingDef['capabilities'] = adminFS.capabilities
existingDef['allowGeometryUpdates'] = adminFS.allowGeometryUpdates
enableResults = adminFS.updateDefinition(json_dict=definition)
if 'error' in enableResults:
return enableResults['error']
adminFS = None
del adminFS
print (enableResults)
return existingDef
#----------------------------------------------------------------------
def enableSync(self, url, definition = None):
"""Enables Sync capability for an AGOL feature service.
Args:
url (str): The URL of the feature service.
definition (dict): A dictionary containing valid definition values. Defaults to ``None``.
Returns:
dict: The result from :py:func:`arcrest.hostedservice.service.AdminFeatureService.updateDefinition`.
"""
adminFS = AdminFeatureService(url=url, securityHandler=self._securityHandler)
cap = str(adminFS.capabilities)
existingDef = {}
enableResults = 'skipped'
if 'Sync' in cap:
return "Sync is already enabled"
else:
capItems = cap.split(',')
capItems.append('Sync')
existingDef['capabilities'] = ','.join(capItems)
enableResults = adminFS.updateDefinition(json_dict=existingDef)
if 'error' in enableResults:
return enableResults['error']
adminFS = None
del adminFS
return enableResults
#----------------------------------------------------------------------
def disableSync(self, url, definition = None):
"""Disables Sync capabilities for an AGOL feature service.
Args:
url (str): The URL of the feature service.
definition (dict): A dictionary containing valid definition values. Defaults to ``None``.
Returns:
dict: The result from :py:func:`arcrest.hostedservice.service.AdminFeatureService.updateDefinition`.
"""
adminFS = AdminFeatureService(url=url, securityHandler=self._securityHandler)
cap = str(adminFS.capabilities)
existingDef = {}
enableResults = 'skipped'
if 'Sync' in cap:
capItems = cap.split(',')
if 'Sync' in capItems:
capItems.remove('Sync')
existingDef['capabilities'] = ','.join(capItems)
enableResults = adminFS.updateDefinition(json_dict=existingDef)
if 'error' in enableResults:
return enableResults['error']
adminFS = None
del adminFS
return enableResults
#----------------------------------------------------------------------
def GetFeatureService(self, itemId, returnURLOnly=False):
"""Obtains a feature service by item ID.
Args:
itemId (str): The feature service's item ID.
returnURLOnly (bool): A boolean value to return the URL of the feature service. Defaults to ``False``.
Returns:
When ``returnURLOnly`` is ``True``, the URL of the feature service is returned.
When ``False``, the result from :py:func:`arcrest.agol.services.FeatureService` or :py:func:`arcrest.ags.services.FeatureService`.
"""
admin = None
item = None
try:
admin = arcrest.manageorg.Administration(securityHandler=self._securityHandler)
if self._securityHandler.valid == False:
self._valid = self._securityHandler.valid
self._message = self._securityHandler.message
return None
item = admin.content.getItem(itemId=itemId)
if item.type == "Feature Service":
if returnURLOnly:
return item.url
else:
fs = arcrest.agol.FeatureService(
url=item.url,
securityHandler=self._securityHandler)
if fs.layers is None or len(fs.layers) == 0 :
fs = arcrest.ags.FeatureService(
url=item.url)
return fs
return None
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "GetFeatureService",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
admin = None
item = None
del item
del admin
gc.collect()
#----------------------------------------------------------------------
def GetLayerFromFeatureServiceByURL(self, url, layerName="", returnURLOnly=False):
"""Obtains a layer from a feature service by URL reference.
Args:
url (str): The URL of the feature service.
layerName (str): The name of the layer. Defaults to ``""``.
returnURLOnly (bool): A boolean value to return the URL of the layer. Defaults to ``False``.
Returns:
When ``returnURLOnly`` is ``True``, the URL of the layer is returned.
When ``False``, the result from :py:func:`arcrest.agol.services.FeatureService` or :py:func:`arcrest.ags.services.FeatureService`.
"""
fs = None
try:
fs = arcrest.agol.FeatureService(
url=url,
securityHandler=self._securityHandler)
return self.GetLayerFromFeatureService(fs=fs,layerName=layerName,returnURLOnly=returnURLOnly)
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "GetLayerFromFeatureServiceByURL",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
fs = None
del fs
gc.collect()
#----------------------------------------------------------------------
def GetLayerFromFeatureService(self, fs, layerName="", returnURLOnly=False):
"""Obtains a layer from a feature service by feature service reference.
Args:
fs (FeatureService): The feature service from which to obtain the layer.
layerName (str): The name of the layer. Defaults to ``""``.
returnURLOnly (bool): A boolean value to return the URL of the layer. Defaults to ``False``.
Returns:
When ``returnURLOnly`` is ``True``, the URL of the layer is returned.
When ``False``, the result from :py:func:`arcrest.agol.services.FeatureService` or :py:func:`arcrest.ags.services.FeatureService`.
"""
layers = None
table = None
layer = None
sublayer = None
try:
layers = fs.layers
if (layers is None or len(layers) == 0) and fs.url is not None:
fs = arcrest.ags.FeatureService(
url=fs.url)
layers = fs.layers
if layers is not None:
for layer in layers:
if layer.name == layerName:
if returnURLOnly:
return fs.url + '/' + str(layer.id)
else:
return layer
elif not layer.subLayers is None:
for sublayer in layer.subLayers:
if sublayer == layerName:
return sublayer
if fs.tables is not None:
for table in fs.tables:
if table.name == layerName:
if returnURLOnly:
return fs.url + '/' + str(layer.id)
else:
return table
return None
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "GetLayerFromFeatureService",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
layers = None
table = None
layer = None
sublayer = None
del layers
del table
del layer
del sublayer
gc.collect()
#----------------------------------------------------------------------
def AddFeaturesToFeatureLayer(self, url, pathToFeatureClass, chunksize=0, lowerCaseFieldNames=False):
"""Appends local features to a hosted feature service layer.
Args:
url (str): The URL of the feature service layer.
pathToFeatureClass (str): The path of the feature class on disk.
chunksize (int): The maximum amount of features to upload at a time. Defaults to 0.
lowerCaseFieldNames (bool): A boolean value indicating if field names should be converted
to lowercase before uploading. Defaults to ``False``.
Returns:
The result from :py:func:`arcrest.agol.services.FeatureLayer.addFeatures`.
Raises:
ArcRestHelperError: if ``arcpy`` can't be found.
Notes:
If publishing to a PostgreSQL database, it is suggested to to set ``lowerCaseFieldNames`` to ``True``.
"""
if arcpyFound == False:
raise common.ArcRestHelperError({
"function": "AddFeaturesToFeatureLayer",
"line": inspect.currentframe().f_back.f_lineno,
"filename": 'featureservicetools',
"synerror": "ArcPy required for this function"
})
fl = None
try:
fl = FeatureLayer(
url=url,
securityHandler=self._securityHandler)
if chunksize > 0:
fc = os.path.basename(pathToFeatureClass)
inDesc = arcpy.Describe(pathToFeatureClass)
oidName = inDesc.oidFieldName
arr = arcpy.da.FeatureClassToNumPyArray(pathToFeatureClass, (oidName))
syncSoFar = 0
messages = {'addResults':[],'errors':[]}
total = len(arr)
errorCount = 0
if total == '0':
print ("0 features in %s" % pathToFeatureClass)
return "0 features in %s" % pathToFeatureClass
print ("%s features in layer" % (total))
arcpy.env.overwriteOutput = True
if int(total) < int(chunksize):
return fl.addFeatures(fc=pathToFeatureClass,lowerCaseFieldNames=lowerCaseFieldNames)
else:
newArr = chunklist(arr,chunksize)
exprList = ["{0} >= {1} AND {0} <= {2}".format(oidName, nArr[0][0], nArr[len(nArr)-1][0])
for nArr in newArr]
for expr in exprList:
UploadLayer = arcpy.MakeFeatureLayer_management(pathToFeatureClass, 'TEMPCOPY', expr).getOutput(0)
#print(arcpy.GetCount_management(in_rows=UploadLayer).getOutput(0) + " features in the chunk")
results = fl.addFeatures(fc=UploadLayer,lowerCaseFieldNames=lowerCaseFieldNames)
chunkCount = arcpy.GetCount_management(in_rows=UploadLayer).getOutput(0)
print(chunkCount + " features in the chunk")
if chunkCount > 0:
if results is not None and 'addResults' in results and results['addResults'] is not None:
featSucces = 0
for result in results['addResults']:
if 'success' in result:
if result['success'] == False:
if 'error' in result:
errorCount = errorCount + 1
print ("\tError info: %s" % (result))
else:
featSucces = featSucces + 1
syncSoFar = syncSoFar + featSucces
print ("%s features added in this chunk" % (featSucces))
print ("%s/%s features added, %s errors" % (syncSoFar,total,errorCount ))
if 'addResults' in messages:
messages['addResults'] = messages['addResults'] + results['addResults']
else:
messages['addResults'] = results['addResults']
else:
messages['errors'] = result
return messages
else:
return fl.addFeatures(fc=pathToFeatureClass,lowerCaseFieldNames=lowerCaseFieldNames)
except arcpy.ExecuteError:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "AddFeaturesToFeatureLayer",
"line": line,
"filename": filename,
"synerror": synerror,
"arcpyError": arcpy.GetMessages(2),
}
)
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "AddFeaturesToFeatureLayer",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
fl = None
del fl
gc.collect()
#----------------------------------------------------------------------
def DeleteFeaturesFromFeatureLayer(self, url, sql, chunksize=0):
"""Removes features from a hosted feature service layer by SQL query.
Args:
url (str): The URL of the feature service layer.
sql (str): The SQL query to apply against the feature service.
Those features that satisfy the query will be deleted.
chunksize (int): The maximum amount of features to remove at a time. Defaults to 0.
Returns:
The result from :py:func:`arcrest.agol.services.FeatureLayer.deleteFeatures`.
Notes:
If you want to delete all features, it is suggested to use the SQL query ``"1=1"``.
"""
fl = None
try:
fl = FeatureLayer(
url=url,
securityHandler=self._securityHandler)
totalDeleted = 0
if chunksize > 0:
qRes = fl.query(where=sql, returnIDsOnly=True)
if 'error' in qRes:
print (qRes)
return qRes
elif 'objectIds' in qRes:
oids = qRes['objectIds']
total = len(oids)
if total == 0:
return {'success':True,'message': "No features matched the query"}
i = 0
print ("%s features to be deleted" % total)
while(i <= len(oids)):
oidsDelete = ','.join(str(e) for e in oids[i:i+chunksize])
if oidsDelete == '':
continue
else:
results = fl.deleteFeatures(objectIds=oidsDelete)
if 'deleteResults' in results:
totalDeleted += len(results['deleteResults'])
print ("%s%% Completed: %s/%s " % (int(totalDeleted / float(total) *100), totalDeleted, total))
i += chunksize
else:
print (results)
return {'success':True,'message': "%s deleted" % totalDeleted}
qRes = fl.query(where=sql, returnIDsOnly=True)
if 'objectIds' in qRes:
oids = qRes['objectIds']
if len(oids)> 0 :
print ("%s features to be deleted" % len(oids))
results = fl.deleteFeatures(where=sql)
if 'deleteResults' in results:
totalDeleted += len(results['deleteResults'])
return {'success':True,'message': "%s deleted" % totalDeleted}
else:
return results
return {'success':True,'message': "%s deleted" % totalDeleted}
else:
print (qRes)
else:
results = fl.deleteFeatures(where=sql)
if results is not None:
if 'deleteResults' in results:
return {'success':True,'message': totalDeleted + len(results['deleteResults'])}
else:
return results
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "DeleteFeaturesFromFeatureLayer",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
fl = None
del fl
gc.collect()
#----------------------------------------------------------------------
def QueryAllFeatures(self, url=None,
where="1=1",
out_fields="*",
timeFilter=None,
geometryFilter=None,
returnFeatureClass=False,
out_fc=None,
outSR=None,
chunksize=1000,
printIndent=""):
"""Performs an SQL query against a hosted feature service layer
and returns all features regardless of service limit.
Args:
url (str): The URL of the feature service layer.
where - the selection sql statement
out_fields - the attribute fields to return
timeFilter - a TimeFilter object where either the start time
or start and end time are defined to limit the
search results for a given time. The values in
the timeFilter should be as UTC timestampes in
milliseconds. No checking occurs to see if they
are in the right format.
geometryFilter - a GeometryFilter object to parse down a given
query by another spatial dataset.
returnFeatureClass - Default False. If true, query will be
returned as feature class
chunksize (int): The maximum amount of features to query at a time. Defaults to 1000.
out_fc - only valid if returnFeatureClass is set to True.
Output location of query.
Output:
A list of Feature Objects (default) or a path to the output featureclass if
returnFeatureClass is set to True.
"""
if (url is None):
return
fl = None
try:
fl = FeatureLayer(url=url, securityHandler=self._securityHandler)
qRes = fl.query(where=where,
returnIDsOnly=True,
timeFilter=timeFilter,
geometryFilter=geometryFilter)
if 'error' in qRes:
print (printIndent + qRes)
return []
elif 'objectIds' in qRes:
oids = qRes['objectIds']
total = len(oids)
if total == 0:
return fl.query(where=where,
returnGeometry=True,
out_fields=out_fields,
timeFilter=timeFilter,
geometryFilter=geometryFilter,
outSR=outSR)
print (printIndent + "%s features to be downloaded" % total)
chunksize = min(chunksize, fl.maxRecordCount)
combinedResults = None
totalQueried = 0
for chunk in chunklist(l=oids, n=chunksize):
oidsQuery = ",".join(map(str, chunk))
if not oidsQuery:
continue
else:
results = fl.query(objectIds=oidsQuery,
returnGeometry=True,
out_fields=out_fields,
timeFilter=timeFilter,
geometryFilter=geometryFilter,
outSR=outSR)
if isinstance(results,FeatureSet):
if combinedResults is None:
combinedResults = results
else:
for feature in results.features:
combinedResults.features.append(feature)
totalQueried += len(results.features)
print(printIndent + "{:.0%} Completed: {}/{}".format(totalQueried / float(total), totalQueried, total))
else:
print (printIndent + results)
if returnFeatureClass == True:
return combinedResults.save(*os.path.split(out_fc))
else:
return combinedResults
else:
print (printIndent + qRes)
except:
line, filename, synerror = trace()
raise common.ArcRestHelperError({
"function": "QueryAllFeatures",
"line": line,
"filename": filename,
"synerror": synerror,
}
)
finally:
fl = None
del fl
gc.collect()