sparclclient 1.2.1.dev7__tar.gz → 1.2.2b1__tar.gz

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.
Files changed (42) hide show
  1. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/.gitignore +1 -0
  2. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/PKG-INFO +2 -2
  3. sparclclient-1.2.2b1/README.md +2 -0
  4. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/pyproject.toml +4 -5
  5. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/source/conf.py +1 -4
  6. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/Results.py +11 -2
  7. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/__init__.py +3 -10
  8. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/client.py +110 -24
  9. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/exceptions.py +3 -1
  10. sparclclient-1.2.2b1/sparcl/notebooks/sparcl-examples.ipynb +1533 -0
  11. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/utils.py +13 -0
  12. sparclclient-1.2.2b1/tests/expected_pat.py +170 -0
  13. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/tests/tests_api.py +15 -11
  14. sparclclient-1.2.1.dev7/README.md +0 -2
  15. sparclclient-1.2.1.dev7/sparcl/notebooks/sparcl-examples.ipynb +0 -1522
  16. sparclclient-1.2.1.dev7/tests/expected_pat.py +0 -114
  17. sparclclient-1.2.1.dev7/unpub-notebooks/SPARCL_client_method_tests.ipynb +0 -2177
  18. sparclclient-1.2.1.dev7/unpub-notebooks/align_spectra.ipynb +0 -1
  19. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/.github/workflows/django.yml +0 -0
  20. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/.pre-commit-config.yaml +0 -0
  21. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/.readthedocs.yaml +0 -0
  22. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/LICENSE +0 -0
  23. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/Makefile +0 -0
  24. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/make.bat +0 -0
  25. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/requirements-client.txt +0 -0
  26. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/requirements-internal.txt +0 -0
  27. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/requirements.txt +0 -0
  28. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/source/index.rst +0 -0
  29. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/source/sparcl.rst +0 -0
  30. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/benchmarks/__init__.py +0 -0
  31. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/benchmarks/benchmarks.py +0 -0
  32. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/conf.py +0 -0
  33. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/fields.py +0 -0
  34. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/gather_2d.py +0 -0
  35. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/resample_spectra.py +0 -0
  36. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/sparc.ini +0 -0
  37. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/type_conversion.py +0 -0
  38. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/sparcl/unsupported.py +0 -0
  39. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/tests/expected_dev1.py +0 -0
  40. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/tests/methods_tests.py +0 -0
  41. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/tests/utils.py +0 -0
  42. {sparclclient-1.2.1.dev7 → sparclclient-1.2.2b1}/tox.ini +0 -0
@@ -1,4 +1,5 @@
1
1
  OBSOLETE_*/
2
+ UNPUBLISHED/
2
3
 
3
4
  # Byte-compiled / optimized / DLL files
4
5
  __pycache__/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sparclclient
3
- Version: 1.2.1.dev7
3
+ Version: 1.2.2b1
4
4
  Summary: A client for getting spectra and meta-data from NOIRLab.
5
5
  Author-email: "S. Pothier" <datalab-spectro@noirlab.edu>
6
6
  Description-Content-Type: text/markdown
@@ -10,5 +10,5 @@ Project-URL: Documentation, https://sparclclient.readthedocs.io/en/latest/
10
10
  Project-URL: Homepage, https://github.com/pypa/sparclclient
11
11
 
12
12
  # sparclclient
13
- Python Client for SPARC (SPectra Analysis and Retrievable Catalog Lab)
13
+ Python Client for SPARCL (SPectra Analysis and Retrievable Catalog Lab)
14
14
 
@@ -0,0 +1,2 @@
1
+ # sparclclient
2
+ Python Client for SPARCL (SPectra Analysis and Retrievable Catalog Lab)
@@ -1,14 +1,12 @@
1
1
  # See:
2
- # https://flit.pypa.io/en/latest/pyproject_toml.html # FLIT
3
- # https://packaging.python.org/en/latest/tutorials/packaging-projects/
4
- # https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/
2
+ # FLIT: https://flit.pypa.io/en/latest/pyproject_toml.html
5
3
  # TOML format: https://toml.io/en/
6
- # https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
4
+
7
5
  #
8
6
  # Updating PyPi:
9
7
  # source venv/bin/activate
10
8
  # flit build
11
- # flit publish
9
+ # flit publish --repository sparclclient
12
10
 
13
11
 
14
12
  [build-system]
@@ -24,6 +22,7 @@ authors = [
24
22
  readme = "README.md"
25
23
  license = {file = "LICENSE"}
26
24
  classifiers = ["License :: OSI Approved :: MIT License"]
25
+ # version is found in: ~/sandbox/sparclclient/sparcl/__init__.py
27
26
  dynamic = ["version", "description"]
28
27
 
29
28
  [project.urls]
@@ -14,12 +14,9 @@
14
14
  import os
15
15
  import re
16
16
  import sys
17
-
18
- sys.path.insert(0, os.path.abspath(".."))
19
-
20
-
21
17
  from sparcl import __version__
22
18
 
19
+ sys.path.insert(0, os.path.abspath(".."))
23
20
 
24
21
  # -- Project information -----------------------------------------------------
25
22
 
@@ -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]) == str:
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]) == int:
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)}
@@ -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.1.dev7"
32
+ # __version__ = "1.2.1b3"
33
+ #__version__ = "1.2.1"
34
+ __version__ = "1.2.2b1"
@@ -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 SPARC Server. Defaults
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 SPARC database.
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 SPARC database.
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 SPARC database.
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
- # dataset_list=None,
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 SPARC database.
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
- res = requests.post(url, json=sspec, timeout=self.timeout)
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 SPARC database.
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 SPARC database.
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 SPARC database.
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 SPARC database.
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 SPARC database.
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 SPARC database.
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 SPARC database by list of
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 SPARC database.
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
- res = requests.post(
707
- url, json=ids, auth=self.session.auth, timeout=self.timeout
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 SPARC database by list of specids.
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 SPARC database.
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.
@@ -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')} " f"[{status.get('errorCode')}]"
26
+ f"{status.get('errorMessage')} "
27
+ f"[{status.get('errorCode')}] "
28
+ f"{status.get('traceback')}"
27
29
  )
28
30
 
29
31