sparclclient 1.2.1.dev7__py2.py3-none-any.whl → 1.2.2b1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sparcl/Results.py +11 -2
- sparcl/__init__.py +3 -10
- sparcl/client.py +110 -24
- sparcl/exceptions.py +3 -1
- sparcl/notebooks/sparcl-examples.ipynb +845 -834
- sparcl/utils.py +13 -0
- {sparclclient-1.2.1.dev7.dist-info → sparclclient-1.2.2b1.dist-info}/METADATA +2 -2
- sparclclient-1.2.2b1.dist-info/RECORD +19 -0
- sparclclient-1.2.1.dev7.dist-info/RECORD +0 -19
- {sparclclient-1.2.1.dev7.dist-info → sparclclient-1.2.2b1.dist-info}/LICENSE +0 -0
- {sparclclient-1.2.1.dev7.dist-info → sparclclient-1.2.2b1.dist-info}/WHEEL +0 -0
sparcl/Results.py
CHANGED
|
@@ -21,6 +21,15 @@ class Results(UserList):
|
|
|
21
21
|
self.fields = client.fields
|
|
22
22
|
self.to_science_fields()
|
|
23
23
|
|
|
24
|
+
# HACK 12/14/2023 -sp- to fix UUID problem presumably
|
|
25
|
+
# produced on stack version upgrade (to Django 4.2, postgres 13+)
|
|
26
|
+
# Done per AB for expediency since real solution will be easier
|
|
27
|
+
# after field-renaming is removed.
|
|
28
|
+
for rec in self.recs:
|
|
29
|
+
if "sparcl_id" in rec:
|
|
30
|
+
rec["sparcl_id"] = str(rec["sparcl_id"])
|
|
31
|
+
# END __init__()
|
|
32
|
+
|
|
24
33
|
# https://docs.python.org/3/library/collections.html#collections.deque.clear
|
|
25
34
|
def clear(self):
|
|
26
35
|
"""Delete the contents of this collection."""
|
|
@@ -132,9 +141,9 @@ class Results(UserList):
|
|
|
132
141
|
# Transform science fields to internal fields
|
|
133
142
|
new_recs = self.science_to_internal_fields()
|
|
134
143
|
# Get the ids or specids from retrieved records
|
|
135
|
-
if type(ids_og[0])
|
|
144
|
+
if type(ids_og[0]) is str:
|
|
136
145
|
ids_re = [f["sparcl_id"] for f in new_recs]
|
|
137
|
-
elif type(ids_og[0])
|
|
146
|
+
elif type(ids_og[0]) is int:
|
|
138
147
|
ids_re = [f["specid"] for f in new_recs]
|
|
139
148
|
# Enumerate the original ids
|
|
140
149
|
dict_og = {x: i for i, x in enumerate(ids_og)}
|
sparcl/__init__.py
CHANGED
|
@@ -26,16 +26,9 @@ __all__ = ["client", "align_records"]
|
|
|
26
26
|
|
|
27
27
|
# must mach: [N!]N(.N)*[{a|b|rc}N][.postN][.devN]
|
|
28
28
|
# Example of a correct version string: '0.4.0a3.dev35'
|
|
29
|
-
# __version__ = '0.4.0b1.dev8'
|
|
30
|
-
# __version__ = '0.4.0b1.dev10'
|
|
31
|
-
# __version__ = '1.0.0'
|
|
32
|
-
# __version__ = '1.0.0b1.dev7'
|
|
33
|
-
# __version__ = '1.0.0b1.dev8'
|
|
34
|
-
# __version__ = '1.0.0b1.dev9'
|
|
35
|
-
# __version__ = '1.0.1b2.dev1'
|
|
36
|
-
# __version__ = '1.1rc1'
|
|
37
|
-
# __version__ = '1.1rc2'
|
|
38
29
|
# __version__ = '1.1'
|
|
39
30
|
# __version__ = '1.2.0b4'
|
|
40
31
|
# __version__ = '1.2.0' # Release
|
|
41
|
-
__version__ = "1.2.
|
|
32
|
+
# __version__ = "1.2.1b3"
|
|
33
|
+
#__version__ = "1.2.1"
|
|
34
|
+
__version__ = "1.2.2b1"
|
sparcl/client.py
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
This module interfaces to the SPARC-Server to get spectra data.
|
|
3
3
|
"""
|
|
4
4
|
# python -m unittest tests.tests_api
|
|
5
|
+
|
|
6
|
+
# ### Run tests against DEV
|
|
7
|
+
# serverurl=http://localhost:8050 python -m unittest tests.tests_api
|
|
8
|
+
#
|
|
9
|
+
# ### Run tests Against PAT Server.
|
|
10
|
+
# export serverurl=https://sparc1.datalab.noirlab.edu/
|
|
11
|
+
# python -m unittest tests.tests_api
|
|
12
|
+
|
|
5
13
|
#
|
|
6
14
|
# Doctest example:
|
|
7
15
|
# cd ~/sandbox/sparclclient
|
|
@@ -14,6 +22,7 @@ This module interfaces to the SPARC-Server to get spectra data.
|
|
|
14
22
|
from urllib.parse import urlencode, urlparse
|
|
15
23
|
from warnings import warn
|
|
16
24
|
import pickle
|
|
25
|
+
import getpass
|
|
17
26
|
|
|
18
27
|
#!from pathlib import Path
|
|
19
28
|
import tempfile
|
|
@@ -22,6 +31,9 @@ import tempfile
|
|
|
22
31
|
# External Packages
|
|
23
32
|
import requests
|
|
24
33
|
|
|
34
|
+
#!from requests.auth import HTTPBasicAuth
|
|
35
|
+
from requests.auth import AuthBase
|
|
36
|
+
|
|
25
37
|
############################################
|
|
26
38
|
# Local Packages
|
|
27
39
|
from sparcl.fields import Fields
|
|
@@ -102,6 +114,19 @@ RESERVED = set([DEFAULT, ALL])
|
|
|
102
114
|
#! return set(lists[0]).intersection(*lists[1:])
|
|
103
115
|
|
|
104
116
|
|
|
117
|
+
class TokenAuth(AuthBase):
|
|
118
|
+
"""Attaches HTTP Token Authentication to the given Request object."""
|
|
119
|
+
|
|
120
|
+
def __init__(self, token):
|
|
121
|
+
# setup any auth-related data here
|
|
122
|
+
self.token = token
|
|
123
|
+
|
|
124
|
+
def __call__(self, request):
|
|
125
|
+
# modify and return the request
|
|
126
|
+
request.headers["Authorization"] = self.token
|
|
127
|
+
return request
|
|
128
|
+
|
|
129
|
+
|
|
105
130
|
###########################
|
|
106
131
|
# ## The Client class
|
|
107
132
|
|
|
@@ -113,7 +138,7 @@ class SparclClient: # was SparclApi()
|
|
|
113
138
|
about the Client and Server that is usefule to Developers.
|
|
114
139
|
|
|
115
140
|
Args:
|
|
116
|
-
url (:obj:`str`, optional): Base URL of
|
|
141
|
+
url (:obj:`str`, optional): Base URL of SPARCL Server. Defaults
|
|
117
142
|
to 'https://astrosparcl.datalab.noirlab.edu'.
|
|
118
143
|
|
|
119
144
|
verbose (:obj:`bool`, optional): Default verbosity is set to
|
|
@@ -142,8 +167,6 @@ class SparclClient: # was SparclApi()
|
|
|
142
167
|
def __init__(
|
|
143
168
|
self,
|
|
144
169
|
*,
|
|
145
|
-
email=None,
|
|
146
|
-
password=None,
|
|
147
170
|
url=_PROD,
|
|
148
171
|
verbose=False,
|
|
149
172
|
show_curl=False,
|
|
@@ -153,11 +176,11 @@ class SparclClient: # was SparclApi()
|
|
|
153
176
|
"""Create client instance."""
|
|
154
177
|
session = requests.Session()
|
|
155
178
|
self.session = session
|
|
156
|
-
|
|
157
|
-
self.session.auth = (email, password) if email and password else None
|
|
179
|
+
self.session.auth = None
|
|
158
180
|
self.rooturl = url.rstrip("/") # eg. "http://localhost:8050"
|
|
159
181
|
self.apiurl = f"{self.rooturl}/sparc"
|
|
160
182
|
self.apiversion = None
|
|
183
|
+
self.token = None
|
|
161
184
|
self.verbose = verbose
|
|
162
185
|
self.show_curl = show_curl # Show CURL equivalent of client method
|
|
163
186
|
#!self.internal_names = internal_names
|
|
@@ -214,11 +237,70 @@ class SparclClient: # was SparclApi()
|
|
|
214
237
|
f"(sparclclient:{self.clientversion},"
|
|
215
238
|
f" api:{self.apiversion},"
|
|
216
239
|
f" {self.apiurl},"
|
|
240
|
+
f" client_hash={ut.githash()},"
|
|
217
241
|
f" verbose={self.verbose},"
|
|
218
242
|
f" connect_timeout={self.c_timeout},"
|
|
219
243
|
f" read_timeout={self.r_timeout})"
|
|
220
244
|
)
|
|
221
245
|
|
|
246
|
+
def login(self, email, password=None):
|
|
247
|
+
if email is None: # "logout"
|
|
248
|
+
old_email = self.session.auth[0] if self.session.auth else None
|
|
249
|
+
self.session.auth = None
|
|
250
|
+
self.token = None
|
|
251
|
+
print(
|
|
252
|
+
f"Logged-out successfully. "
|
|
253
|
+
f" Previously logged-in with email {old_email}."
|
|
254
|
+
)
|
|
255
|
+
return None
|
|
256
|
+
if password is None:
|
|
257
|
+
password = getpass.getpass()
|
|
258
|
+
# url = f"{self.apiurl}/get_token/"
|
|
259
|
+
url = "http://localhost:8060/api/get_token/"
|
|
260
|
+
res = requests.post(
|
|
261
|
+
url,
|
|
262
|
+
json=dict(email=email, password=password),
|
|
263
|
+
timeout=self.timeout,
|
|
264
|
+
)
|
|
265
|
+
self.session.auth = None
|
|
266
|
+
self.token = None
|
|
267
|
+
try:
|
|
268
|
+
res.raise_for_status()
|
|
269
|
+
#!print(f"DBG: {res.content=}")
|
|
270
|
+
self.token = res.json()
|
|
271
|
+
self.session.auth = (email, password)
|
|
272
|
+
except Exception as err:
|
|
273
|
+
msg = f"Could not login with given credentials. {err=}"
|
|
274
|
+
return msg
|
|
275
|
+
|
|
276
|
+
print(f"Logged in successfully with {email=}")
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
def logout(self):
|
|
280
|
+
return self.login(None)
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def authorized(self):
|
|
284
|
+
auth = TokenAuth(self.token) if self.token else None
|
|
285
|
+
username = self.session.auth[0] if self.session.auth else "Anonymous"
|
|
286
|
+
response = requests.get(
|
|
287
|
+
f"{self.apiurl}/auth_status/", auth=auth, timeout=self.timeout
|
|
288
|
+
)
|
|
289
|
+
auth_status = response.json()
|
|
290
|
+
print(f"{auth_status=}")
|
|
291
|
+
|
|
292
|
+
all_private_drs = set(auth_status.get("All_Private_DataReleases"))
|
|
293
|
+
all_drs = self.fields.all_drs
|
|
294
|
+
auth_drs = set(auth_status.get("Authorized_DataReleases"))
|
|
295
|
+
res = dict(
|
|
296
|
+
Loggedin_As=username, # email
|
|
297
|
+
Authorized_Datasets=auth_drs,
|
|
298
|
+
Unauthorized_Datasets=all_private_drs - auth_drs,
|
|
299
|
+
All_Private_Datasets=all_private_drs,
|
|
300
|
+
All_Datasets=all_drs,
|
|
301
|
+
)
|
|
302
|
+
return res
|
|
303
|
+
|
|
222
304
|
@property
|
|
223
305
|
def all_datasets(self):
|
|
224
306
|
"""Set of all DataSets available from Server"""
|
|
@@ -233,7 +315,7 @@ class SparclClient: # was SparclApi()
|
|
|
233
315
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
234
316
|
which to get the default fields. Defaults to None, which
|
|
235
317
|
will return the intersection of default fields in all
|
|
236
|
-
data sets hosted on the
|
|
318
|
+
data sets hosted on the SPARCL database.
|
|
237
319
|
|
|
238
320
|
Returns:
|
|
239
321
|
List of fields tagged as 'default' from DATASET_LIST.
|
|
@@ -264,7 +346,7 @@ class SparclClient: # was SparclApi()
|
|
|
264
346
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
265
347
|
which to get all fields. Defaults to None, which
|
|
266
348
|
will return the intersection of all fields in all
|
|
267
|
-
data sets hosted on the
|
|
349
|
+
data sets hosted on the SPARCL database.
|
|
268
350
|
|
|
269
351
|
Returns:
|
|
270
352
|
List of fields tagged as 'all' from DATASET_LIST.
|
|
@@ -322,7 +404,7 @@ class SparclClient: # was SparclApi()
|
|
|
322
404
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
323
405
|
which to get available fields. Defaults to None, which
|
|
324
406
|
will return the intersection of all available fields in
|
|
325
|
-
all data sets hosted on the
|
|
407
|
+
all data sets hosted on the SPARCL database.
|
|
326
408
|
|
|
327
409
|
Returns:
|
|
328
410
|
Set of fields available from data sets in DATASET_LIST.
|
|
@@ -364,12 +446,14 @@ class SparclClient: # was SparclApi()
|
|
|
364
446
|
outfields=None,
|
|
365
447
|
*,
|
|
366
448
|
constraints={}, # dict(fname) = [op, param, ...]
|
|
367
|
-
|
|
449
|
+
#! exclude_unauth = True, # Not implemented yet
|
|
368
450
|
limit=500,
|
|
369
451
|
sort=None,
|
|
452
|
+
# count=False,
|
|
453
|
+
# dataset_list=None,
|
|
370
454
|
verbose=None,
|
|
371
455
|
):
|
|
372
|
-
"""Find records in the
|
|
456
|
+
"""Find records in the SPARCL database.
|
|
373
457
|
|
|
374
458
|
Args:
|
|
375
459
|
outfields (:obj:`list`, optional): List of fields to return.
|
|
@@ -429,6 +513,7 @@ class SparclClient: # was SparclApi()
|
|
|
429
513
|
}
|
|
430
514
|
uparams = dict(
|
|
431
515
|
limit=limit,
|
|
516
|
+
#! count='Y' if count else 'N'
|
|
432
517
|
)
|
|
433
518
|
if sort is not None:
|
|
434
519
|
uparams["sort"] = sort
|
|
@@ -445,7 +530,8 @@ class SparclClient: # was SparclApi()
|
|
|
445
530
|
cmd = ut.curl_find_str(sspec, self.rooturl, qstr=qstr)
|
|
446
531
|
print(cmd)
|
|
447
532
|
|
|
448
|
-
|
|
533
|
+
auth = TokenAuth(self.token) if self.token else None
|
|
534
|
+
res = requests.post(url, json=sspec, auth=auth, timeout=self.timeout)
|
|
449
535
|
|
|
450
536
|
if res.status_code != 200:
|
|
451
537
|
if verbose and ("traceback" in res.json()):
|
|
@@ -461,14 +547,14 @@ class SparclClient: # was SparclApi()
|
|
|
461
547
|
self, uuid_list, *, dataset_list=None, countOnly=False, verbose=False
|
|
462
548
|
):
|
|
463
549
|
"""Return the subset of sparcl_ids in the given uuid_list that are
|
|
464
|
-
NOT stored in the
|
|
550
|
+
NOT stored in the SPARCL database.
|
|
465
551
|
|
|
466
552
|
Args:
|
|
467
553
|
uuid_list (:obj:`list`): List of sparcl_ids.
|
|
468
554
|
|
|
469
555
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
470
556
|
which to find missing sparcl_ids. Defaults to None, meaning
|
|
471
|
-
all data sets hosted on the
|
|
557
|
+
all data sets hosted on the SPARCL database.
|
|
472
558
|
|
|
473
559
|
countOnly (:obj:`bool`, optional): Set to True to return only
|
|
474
560
|
a count of the missing sparcl_ids from the uuid_list.
|
|
@@ -479,7 +565,7 @@ class SparclClient: # was SparclApi()
|
|
|
479
565
|
|
|
480
566
|
Returns:
|
|
481
567
|
A list of the subset of sparcl_ids in the given uuid_list that
|
|
482
|
-
are NOT stored in the
|
|
568
|
+
are NOT stored in the SPARCL database.
|
|
483
569
|
|
|
484
570
|
Example:
|
|
485
571
|
>>> client = SparclClient()
|
|
@@ -514,14 +600,14 @@ class SparclClient: # was SparclApi()
|
|
|
514
600
|
self, specid_list, *, dataset_list=None, countOnly=False, verbose=False
|
|
515
601
|
):
|
|
516
602
|
"""Return the subset of specids in the given specid_list that are
|
|
517
|
-
NOT stored in the
|
|
603
|
+
NOT stored in the SPARCL database.
|
|
518
604
|
|
|
519
605
|
Args:
|
|
520
606
|
specid_list (:obj:`list`): List of specids.
|
|
521
607
|
|
|
522
608
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
523
609
|
which to find missing specids. Defaults to None, meaning
|
|
524
|
-
all data sets hosted on the
|
|
610
|
+
all data sets hosted on the SPARCL database.
|
|
525
611
|
|
|
526
612
|
countOnly (:obj:`bool`, optional): Set to True to return only
|
|
527
613
|
a count of the missing specids from the specid_list.
|
|
@@ -532,7 +618,7 @@ class SparclClient: # was SparclApi()
|
|
|
532
618
|
|
|
533
619
|
Returns:
|
|
534
620
|
A list of the subset of specids in the given specid_list that
|
|
535
|
-
are NOT stored in the
|
|
621
|
+
are NOT stored in the SPARCL database.
|
|
536
622
|
|
|
537
623
|
Example:
|
|
538
624
|
>>> client = SparclClient(url=_PAT)
|
|
@@ -598,7 +684,7 @@ class SparclClient: # was SparclApi()
|
|
|
598
684
|
limit=500,
|
|
599
685
|
verbose=None,
|
|
600
686
|
):
|
|
601
|
-
"""Retrieve spectra records from the
|
|
687
|
+
"""Retrieve spectra records from the SPARCL database by list of
|
|
602
688
|
sparcl_ids.
|
|
603
689
|
|
|
604
690
|
Args:
|
|
@@ -610,7 +696,7 @@ class SparclClient: # was SparclApi()
|
|
|
610
696
|
|
|
611
697
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
612
698
|
which to retrieve spectra data. Defaults to None, meaning all
|
|
613
|
-
data sets hosted on the
|
|
699
|
+
data sets hosted on the SPARCL database.
|
|
614
700
|
|
|
615
701
|
limit (:obj:`int`, optional): Maximum number of records to
|
|
616
702
|
return. Defaults to 500. Maximum allowed is 24,000.
|
|
@@ -703,9 +789,8 @@ class SparclClient: # was SparclApi()
|
|
|
703
789
|
print(cmd)
|
|
704
790
|
|
|
705
791
|
try:
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
)
|
|
792
|
+
auth = TokenAuth(self.token) if self.token else None
|
|
793
|
+
res = requests.post(url, json=ids, auth=auth, timeout=self.timeout)
|
|
709
794
|
except requests.exceptions.ConnectTimeout as reCT:
|
|
710
795
|
raise ex.UnknownSparcl(f"ConnectTimeout: {reCT}")
|
|
711
796
|
except requests.exceptions.ReadTimeout as reRT:
|
|
@@ -782,7 +867,8 @@ class SparclClient: # was SparclApi()
|
|
|
782
867
|
limit=500,
|
|
783
868
|
verbose=False,
|
|
784
869
|
):
|
|
785
|
-
"""Retrieve spectra records from the
|
|
870
|
+
"""Retrieve spectra records from the SPARCL database by list of
|
|
871
|
+
specids.
|
|
786
872
|
|
|
787
873
|
Args:
|
|
788
874
|
specid_list (:obj:`list`): List of specids.
|
|
@@ -793,7 +879,7 @@ class SparclClient: # was SparclApi()
|
|
|
793
879
|
|
|
794
880
|
dataset_list (:obj:`list`, optional): List of data sets from
|
|
795
881
|
which to retrieve spectra data. Defaults to None, meaning all
|
|
796
|
-
data sets hosted on the
|
|
882
|
+
data sets hosted on the SPARCL database.
|
|
797
883
|
|
|
798
884
|
limit (:obj:`int`, optional): Maximum number of records to
|
|
799
885
|
return. Defaults to 500. Maximum allowed is 24,000.
|
sparcl/exceptions.py
CHANGED
|
@@ -23,7 +23,9 @@ def genSparclException(response, verbose=False):
|
|
|
23
23
|
return BadSearchConstraint(status.get("errorMessage"))
|
|
24
24
|
else:
|
|
25
25
|
return UnknownServerError(
|
|
26
|
-
f"{status.get('errorMessage')} "
|
|
26
|
+
f"{status.get('errorMessage')} "
|
|
27
|
+
f"[{status.get('errorCode')}] "
|
|
28
|
+
f"{status.get('traceback')}"
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
|