3232import logging
3333from requests import Session , codes
3434
35- from pygeoapi .crs import crs_transform , get_srid
35+ from pygeoapi .crs import get_srid
3636from pygeoapi .provider .base import (BaseProvider , ProviderConnectionError ,
3737 ProviderTypeError , ProviderQueryError )
3838from pygeoapi .util import format_datetime
@@ -60,14 +60,19 @@ def __init__(self, provider_def):
6060 super ().__init__ (provider_def )
6161
6262 self .url = f'{ self .data } /query'
63- self .crs = get_srid (self .storage_crs )
63+ self .srid = get_srid (self .storage_crs )
6464 self .username = provider_def .get ('username' )
6565 self .password = provider_def .get ('password' )
6666 self .token_url = provider_def .get ('token_service' , ARCGIS_URL )
6767 self .token_referer = provider_def .get ('referer' , GENERATE_TOKEN_URL )
6868 self .token = None
6969 self .session = Session ()
7070
71+ self .using_deafult_id = any (
72+ kw == self .id_field
73+ for kw in ['OBJECTID' , 'objectid' , 'fid' ]
74+ )
75+
7176 self .login ()
7277 self .get_fields ()
7378
@@ -80,13 +85,17 @@ def get_fields(self):
8085
8186 if not self ._fields :
8287 # Load fields
83- params = {'f' : 'pjson' }
84- resp = self .get_response (self .data , params = params )
88+ try :
89+ resp = self .get_response (self .data , params = {'f' : 'pjson' })
90+ except ProviderConnectionError as err :
91+ msg = f'Could not access resource { self .data } : { err } '
92+ LOGGER .error (msg )
93+ return {}
8594
8695 if resp .get ('error' ) is not None :
8796 msg = f"Connection error: { resp ['error' ]['message' ]} "
8897 LOGGER .error (msg )
89- raise ProviderConnectionError ( msg )
98+ return {}
9099
91100 try :
92101 # Verify Feature/Map Service supports required capabilities
@@ -108,10 +117,10 @@ def get_fields(self):
108117
109118 return self ._fields
110119
111- @crs_transform
112120 def query (self , offset = 0 , limit = 10 , resulttype = 'results' ,
113121 bbox = [], datetime_ = None , properties = [], sortby = [],
114- select_properties = [], skip_geometry = False , q = None , ** kwargs ):
122+ select_properties = [], skip_geometry = False ,
123+ crs_transform_spec = None , ** kwargs ):
115124 """
116125 ESRI query
117126
@@ -124,7 +133,7 @@ def query(self, offset=0, limit=10, resulttype='results',
124133 :param sortby: list of dicts (property, order)
125134 :param select_properties: list of property names
126135 :param skip_geometry: bool of whether to skip geometry (default False)
127- :param q: full-text search term(s)
136+ :param crs_transform_spec: `CrsTransformSpec` instance, optional
128137
129138 :returns: `dict` of GeoJSON FeatureCollection
130139 """
@@ -133,7 +142,7 @@ def query(self, offset=0, limit=10, resulttype='results',
133142
134143 params = {
135144 'f' : 'geoJSON' ,
136- 'outSR' : self .crs ,
145+ 'outSR' : self ._get_srid ( crs_transform_spec ) ,
137146 'outFields' : self ._make_fields (select_properties ),
138147 'where' : self ._make_where (properties , datetime_ )
139148 }
@@ -166,30 +175,41 @@ def query(self, offset=0, limit=10, resulttype='results',
166175
167176 return fc
168177
169- @crs_transform
170- def get (self , identifier , ** kwargs ):
178+ def get (self , identifier , crs_transform_spec = None , ** kwargs ):
171179 """
172180 Query ESRI by id
173181
174182 :param identifier: feature id
183+ :param crs_transform_spec: `CrsTransformSpec` instance, optional
175184
176185 :returns: dict of single GeoJSON feature
177186 """
178187
179188 LOGGER .debug (f'Fetching item: { identifier } ' )
180189 params = {
181190 'f' : 'geoJSON' ,
182- 'outSR' : self .crs ,
183- 'objectIds' : identifier ,
191+ 'outSR' : self ._get_srid (crs_transform_spec ),
184192 'outFields' : self ._make_fields ()
185193 }
186194
187- resp = self .get_response (self .url , params = params )
195+ if self .using_deafult_id :
196+ params ['objectIds' ] = identifier
197+ else :
198+ params ['where' ] = self ._make_where (
199+ [(self .id_field , identifier )]
200+ )
201+
188202 LOGGER .debug ('Returning item' )
189- return resp ['features' ].pop ()
203+ [feature ] = self ._make_features (
204+ self .get_response (params = params )
205+ )
206+
207+ return feature
190208
191209 def login (self ):
192- # Generate token from username and password
210+ """
211+ Generate login token from username and password
212+ """
193213 if self .token is None :
194214
195215 if None in [self .username , self .password ]:
@@ -211,7 +231,17 @@ def login(self):
211231 'X-Esri-Authorization' : f'Bearer { self .token } '
212232 })
213233
214- def get_response (self , url , ** kwargs ):
234+ def get_response (self , url : str = None , ** kwargs ):
235+ """
236+ Get response from ESRI service
237+
238+ :param url: `str` of ESRI service URL if not using default
239+
240+ :returns: `dict` of ESRI response
241+ """
242+ if url is None :
243+ url = self .url
244+
215245 # Form URL for GET request
216246 LOGGER .debug ('Sending query' )
217247 with self .session .get (url , ** kwargs ) as r :
@@ -314,9 +344,22 @@ def _get_count(self, params):
314344 params ['returnCountOnly' ] = 'true'
315345 params ['f' ] = 'pjson'
316346
317- response = self .get_response (self . url , params = params )
347+ response = self .get_response (params = params )
318348 return response .get ('count' , 0 )
319349
350+ def _get_srid (self , crs_transform_spec ):
351+ """
352+ Get SRID from CrsTransformSpec
353+
354+ :param crs_transform_spec: `CrsTransformSpec` instance
355+
356+ :returns: `int` of SRID
357+ """
358+ if crs_transform_spec is not None :
359+ return get_srid (crs_transform_spec .target_crs )
360+
361+ return self .srid
362+
320363 def _get_all (self , params , hits_ ):
321364 """
322365 Get all features from query args
@@ -329,7 +372,9 @@ def _get_all(self, params, hits_):
329372 params = deepcopy (params )
330373
331374 # Return feature collection
332- features = self .get_response (self .url , params = params ).get ('features' )
375+ features = self ._make_features (
376+ self .get_response (params = params )
377+ )
333378 step = len (features )
334379
335380 # Query if values are less than expected
@@ -338,15 +383,37 @@ def _get_all(self, params, hits_):
338383 params ['resultOffset' ] += step
339384 params ['resultRecordCount' ] += step
340385
341- fs = self .get_response (self .url , params = params ).get ('features' )
386+ fs = self ._make_features (
387+ self .get_response (params = params )
388+ )
342389 if len (fs ) != 0 :
343390 features .extend (fs )
344391 else :
345392 break
346393
347394 return features
348395
396+ def _make_features (self , feature_collection : dict = {}):
397+ """
398+ Make a feature from features list
399+
400+ :param features: `dict` of features
401+
402+ :returns: `dict` of single feature
403+ """
404+ features = feature_collection .get ('features' , [])
405+
406+ for feature in features :
407+ if not self .using_deafult_id :
408+ feature ['id' ] = \
409+ feature ['properties' ][self .id_field ]
410+
411+ return features
412+
349413 def __exit__ (self , ** kwargs ):
414+ """
415+ Exit and close session
416+ """
350417 self .session .close ()
351418
352419 def __repr__ (self ):
0 commit comments