12
12
import requests
13
13
from numpy import ma
14
14
from urllib .parse import urlencode
15
+ from urllib .error import HTTPError
15
16
16
17
from ..utils .class_or_instance import class_or_instance
17
18
from ..utils import async_to_sync , commons
@@ -104,15 +105,15 @@ def __init__(self, url=None, tap_plus_handler=None, verbose=None,
104
105
105
106
super (CadcClass , self ).__init__ ()
106
107
self .baseurl = url
108
+ # _auth_session contains the credentials that are used by both
109
+ # the cadc tap and cadc datalink services
107
110
if auth_session :
108
111
self ._auth_session = auth_session
109
112
else :
110
- self ._auth_session = None
113
+ self ._auth_session = authsession . AuthSession ()
111
114
112
115
@property
113
116
def cadctap (self ):
114
- if not self ._auth_session :
115
- self ._auth_session = authsession .AuthSession ()
116
117
if not hasattr (self , '_cadctap' ):
117
118
if self .baseurl is None :
118
119
self .baseurl = get_access_url (self .CADCTAP_SERVICE_URI )
@@ -125,6 +126,13 @@ def cadctap(self):
125
126
self .baseurl , session = self ._auth_session )
126
127
return self ._cadctap
127
128
129
+ @property
130
+ def cadcdatalink (self ):
131
+ if not hasattr (self , '_datalink' ):
132
+ self ._datalink = pyvo .dal .adhoc .DatalinkService (
133
+ self .data_link_url , session = self ._auth_session )
134
+ return self ._datalink
135
+
128
136
@property
129
137
def data_link_url (self ):
130
138
if not hasattr (self , '_data_link_url' ):
@@ -154,9 +162,9 @@ def login(self, user=None, password=None, certificate_file=None):
154
162
# start with a new session
155
163
if not isinstance (self .cadctap ._session , (requests .Session ,
156
164
authsession .AuthSession )):
157
- raise TypeError ('Cannot login with user provided session that is '
158
- 'not an pyvo.authsession.AuthSession or '
159
- 'requests.Session' )
165
+ raise AttributeError ('Cannot login with user provided session that is '
166
+ 'not an pyvo.authsession.AuthSession or '
167
+ 'requests.Session' )
160
168
if not certificate_file and not (user and password ):
161
169
raise AttributeError ('login credentials missing (user/password '
162
170
'or certificate)' )
@@ -216,13 +224,25 @@ def logout(self, verbose=None):
216
224
if verbose is not None :
217
225
warnings .warn ('verbose deprecated since 0.4.0' )
218
226
219
- # the only way to ensure complete logout is to start with a new
220
- # session. This is mainly because of certificates. Adding cert
221
- # argument to a session already in use does not force it to
222
- # re-do the HTTPS hand shake
223
- self .cadctap ._session = authsession .AuthSession ()
224
- self .cadctap ._session .update_from_capabilities (
225
- self .cadctap .capabilities )
227
+ if isinstance (self ._auth_session , pyvo .auth .AuthSession ):
228
+ # Remove the existing credentials (if any)
229
+ # PyVO should provide this reset credentials functionality
230
+ # TODO - this should be implemented in PyVO to avoid this deep
231
+ # intrusion into that package
232
+ self ._auth_session .credentials .credentials = \
233
+ {key : value for (key , value ) in self ._auth_session .credentials .credentials .items ()
234
+ if key == pyvo .auth .securitymethods .ANONYMOUS }
235
+ elif isinstance (self ._auth_session , requests .Session ):
236
+ # the only way to ensure complete logout is to start with a new
237
+ # session. This is mainly because of certificates. Removing cert
238
+ # argument to a session already in use does not force it to
239
+ # re-do the HTTPS hand shake
240
+ self ._auth_session = requests .Session ()
241
+ self .cadctap ._session = self ._auth_session
242
+ self .cadcdatalink ._session = self ._auth_session
243
+ else :
244
+ raise RuntimeError (
245
+ 'Do not know how to log out from custom session' )
226
246
227
247
@class_or_instance
228
248
def query_region_async (self , coordinates , radius = 0.016666666666667 * u .deg ,
@@ -271,7 +291,7 @@ def query_name_async(self, name):
271
291
272
292
Parameters
273
293
----------
274
- name: str
294
+ name : str
275
295
name of object to query for
276
296
277
297
Returns
@@ -353,7 +373,7 @@ def get_images(self, coordinates, radius,
353
373
for fn in filenames :
354
374
try :
355
375
images .append (fn .get_fits ())
356
- except requests .exceptions .HTTPError as err :
376
+ except ( requests .exceptions .HTTPError , HTTPError ) as err :
357
377
# Catch HTTPError if user is unauthorized to access file
358
378
log .debug (
359
379
"{} - Problem retrieving the file: {}" .
@@ -456,7 +476,8 @@ def get_image_list(self, query_result, coordinates, radius):
456
476
range (0 , len (publisher_ids ), batch_size )):
457
477
datalink = pyvo .dal .adhoc .DatalinkResults .from_result_url (
458
478
'{}?{}' .format (self .data_link_url ,
459
- urlencode ({'ID' : pid_sublist }, True )))
479
+ urlencode ({'ID' : pid_sublist }, True ),
480
+ session = self .cadcdatalink ._session ))
460
481
for service_def in datalink .bysemantics ('#cutout' ):
461
482
access_url = service_def .access_url
462
483
if isinstance (access_url , bytes ): # ASTROPY_LT_4_1
@@ -523,7 +544,8 @@ def get_data_urls(self, query_result, include_auxiliaries=False):
523
544
datalink = pyvo .dal .adhoc .DatalinkResults .from_result_url (
524
545
'{}?{}' .format (self .data_link_url ,
525
546
urlencode ({'ID' : pid_sublist ,
526
- 'REQUEST' : 'downloads-only' }, True )))
547
+ 'REQUEST' : 'downloads-only' }, True )),
548
+ session = self .cadcdatalink ._session )
527
549
for service_def in datalink :
528
550
if service_def .semantics in ['http://www.opencadc.org/caom2#pkg' , '#package' ]:
529
551
# TODO http://www.openadc.org/caom2#pkg has been replaced
@@ -582,7 +604,8 @@ def get_table(self, table, verbose=None):
582
604
if table == t .name :
583
605
return t
584
606
585
- def exec_sync (self , query , maxrec = None , uploads = None , output_file = None ):
607
+ def exec_sync (self , query , maxrec = None , uploads = None , output_file = None ,
608
+ output_format = 'votable' ):
586
609
"""
587
610
Run a query and return the results or save them in an output_file
588
611
@@ -592,10 +615,13 @@ def exec_sync(self, query, maxrec=None, uploads=None, output_file=None):
592
615
SQL to execute
593
616
maxrec : int
594
617
the maximum records to return. defaults to the service default
595
- uploads:
618
+ uploads :
596
619
Temporary tables to upload and run with the queries
597
- output_file: str or file handler:
620
+ output_file : str or file handler
598
621
File to save the results to
622
+ output_format :
623
+ Format of the output (default is basic). Must be one
624
+ of the formats supported by `astropy.table`
599
625
600
626
Returns
601
627
-------
@@ -611,10 +637,12 @@ def exec_sync(self, query, maxrec=None, uploads=None, output_file=None):
611
637
result = response .to_table ()
612
638
if output_file :
613
639
if isinstance (output_file , str ):
614
- with open (output_file , 'bw' ) as f :
615
- f .write (result )
640
+ fname = output_file
641
+ elif hasattr (output_file , 'name' ):
642
+ fname = output_file .name
616
643
else :
617
- output_file .write (result )
644
+ raise AttributeError ('Not a valid file name or file handler' )
645
+ result .write (fname , format = output_format , overwrite = True )
618
646
return result
619
647
620
648
def create_async (self , query , maxrec = None , uploads = None ):
@@ -681,9 +709,9 @@ def run_query(self, query, operation, output_file=None,
681
709
when the job is executed in asynchronous mode,
682
710
this flag specifies whether the execution will wait until results
683
711
are available
684
- upload_resource: str, optional, default None
712
+ upload_resource : str, optional, default None
685
713
resource to be uploaded to UPLOAD_SCHEMA
686
- upload_table_name: str, required if uploadResource is provided,
714
+ upload_table_name : str, required if uploadResource is provided,
687
715
default None
688
716
resource temporary table name associated to the uploaded resource
689
717
@@ -712,7 +740,7 @@ def load_async_job(self, jobid, verbose=None):
712
740
warnings .warn ('verbose deprecated since 0.4.0' )
713
741
714
742
return pyvo .dal .AsyncTAPJob ('{}/async/{}' .format (
715
- self .cadctap .baseurl , jobid ))
743
+ self .cadctap .baseurl , jobid ), session = self . _auth_session )
716
744
717
745
def list_async_jobs (self , phases = None , after = None , last = None ,
718
746
short_description = True , verbose = None ):
@@ -721,13 +749,13 @@ def list_async_jobs(self, phases=None, after=None, last=None,
721
749
722
750
Parameters
723
751
----------
724
- phases: list of str
752
+ phases : list of str
725
753
Union of job phases to filter the results by.
726
- after: datetime
754
+ after : datetime
727
755
Return only jobs created after this datetime
728
- last: int
756
+ last : int
729
757
Return only the most recent number of jobs
730
- short_description: flag - True or False
758
+ short_description : flag - True or False
731
759
If True, the jobs in the list will contain only the information
732
760
corresponding to the TAP ShortJobDescription object (job ID, phase,
733
761
run ID, owner ID and creation ID) whereas if False, a separate GET
@@ -783,12 +811,19 @@ def get_access_url(service, capability=None):
783
811
"""
784
812
Returns the URL corresponding to a service by doing a lookup in the cadc
785
813
registry. It returns the access URL corresponding to cookie authentication.
786
- :param service: the service the capability belongs to. It can be identified
787
- by a CADC uri ('ivo://cadc.nrc.ca/) which is looked up in the CADC registry
788
- or by the URL where the service capabilities is found.
789
- :param capability: uri representing the capability for which the access
790
- url is sought
791
- :return: the access url
814
+
815
+ Parameters
816
+ ----------
817
+ service : str
818
+ the service the capability belongs to. It can be identified
819
+ by a CADC uri ('ivo://cadc.nrc.ca/) which is looked up in the CADC registry
820
+ or by the URL where the service capabilities is found.
821
+ capability : str
822
+ uri representing the capability for which the access url is sought
823
+
824
+ Returns
825
+ -------
826
+ The access url
792
827
793
828
Note
794
829
------
0 commit comments